Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/tools/syscalls/config.lua
39476 views
1
--
2
-- SPDX-License-Identifier: BSD-2-Clause
3
--
4
-- Copyright (c) 2021-2024 SRI International
5
-- Copyright (c) 2024 Tyler Baxter <[email protected]>
6
-- Copyright (c) 2023 Warner Losh <[email protected]>
7
-- Copyright (c) 2019 Kyle Evans <[email protected]>
8
--
9
10
--
11
-- Code to read in the config file that drives this. Since we inherit from the
12
-- FreeBSD makesyscall.sh legacy, all config is done through a config file that
13
-- sets a number of variables (as noted below); it used to be a .sh file that
14
-- was sourced in. This dodges the need to write a command line parser.
15
--
16
17
local util = require("tools.util")
18
19
--
20
-- Global config map.
21
-- Default configuration is native. Any of these may get replaced by an
22
-- optionally specified configuration file.
23
--
24
local config = {
25
sysnames = "syscalls.c",
26
syshdr = "../sys/syscall.h",
27
syshdr_extra = nil;
28
sysmk = "/dev/null",
29
syssw = "init_sysent.c",
30
systrace = "systrace_args.c",
31
sysproto = "../sys/sysproto.h",
32
libsysmap = "/dev/null",
33
libsys_h = "/dev/null",
34
sysproto_h = "_SYS_SYSPROTO_H_",
35
syscallprefix = "SYS_",
36
switchname = "sysent",
37
namesname = "syscallnames",
38
abi_flags = {},
39
abi_func_prefix = "",
40
abi_type_suffix = "",
41
abi_long = "long",
42
abi_u_long = "u_long",
43
abi_semid_t = "semid_t",
44
abi_size_t = "size_t",
45
abi_ptr_array_t = "",
46
abi_headers = "",
47
abi_intptr_t = "intptr_t",
48
ptr_intptr_t_cast = "intptr_t",
49
obsol = {},
50
unimpl = {},
51
compat_set = "native",
52
mincompat = 0,
53
-- System calls that require ABI-specific handling.
54
syscall_abi_change = {},
55
-- System calls that appear to require handling, but don't.
56
syscall_no_abi_change = {},
57
-- Keep track of modifications if there are.
58
modifications = {},
59
-- Stores compat_sets from syscalls.conf; config.mergeCompat()
60
-- instantiates.
61
compat_options = {},
62
}
63
64
--
65
-- For each entry, the ABI flag is the key. One may also optionally provide an
66
-- expr, which are contained in an array associated with each key; expr gets
67
-- applied to each argument type to indicate whether this argument is subject to
68
-- ABI change given the configured flags.
69
--
70
config.known_abi_flags = {
71
long_size = {
72
"_Contains[a-z_]*_long_",
73
"^long [a-z0-9_]+$",
74
"long [*]",
75
"size_t [*]",
76
-- semid_t is not included because it is only used
77
-- as an argument or written out individually and
78
-- said writes are handled by the ksem framework.
79
-- Technically a sign-extension issue exists for
80
-- arguments, but because semid_t is actually a file
81
-- descriptor negative 32-bit values are invalid
82
-- regardless of sign-extension.
83
},
84
time_t_size = {
85
"_Contains[a-z_]*_timet_",
86
},
87
pointer_args = {
88
-- no expr
89
},
90
pointer_size = {
91
"_Contains[a-z_]*_ptr_",
92
"[*][*]",
93
},
94
pair_64bit = {
95
"^dev_t[ ]*$",
96
"^id_t[ ]*$",
97
"^off_t[ ]*$",
98
},
99
}
100
101
-- All compat option entries should have five entries:
102
-- definition: The preprocessor macro that will be set for this.
103
-- compatlevel: The level this compatibility should be included at. This
104
-- generally represents the version of FreeBSD that it is compatible
105
-- with, but ultimately it's just the level of mincompat in which it's
106
-- included.
107
-- flag: The name of the flag in syscalls.master.
108
-- prefix: The prefix to use for _args and syscall prototype. This will be
109
-- used as-is, without "_" or any other character appended.
110
-- descr: The description of this compat option in init_sysent.c comments.
111
-- The special "stdcompat" entry will cause the other five to be autogenerated.
112
local compat_option_sets = {
113
native = {
114
{
115
definition = "COMPAT_43",
116
compatlevel = 3,
117
flag = "COMPAT",
118
prefix = "o",
119
descr = "old",
120
},
121
{ stdcompat = "FREEBSD4" },
122
{ stdcompat = "FREEBSD6" },
123
{ stdcompat = "FREEBSD7" },
124
{ stdcompat = "FREEBSD10" },
125
{ stdcompat = "FREEBSD11" },
126
{ stdcompat = "FREEBSD12" },
127
{ stdcompat = "FREEBSD13" },
128
{ stdcompat = "FREEBSD14" },
129
},
130
}
131
132
--
133
-- config looks like a shell script; in fact, the previous makesyscalls.sh
134
-- script actually sourced it in. It had a pretty common format, so we should
135
-- be fine to make various assumptions.
136
--
137
-- This function processes config to be merged into our global config map with
138
-- config.merge(). It aborts if there's malformed lines and returns NIL and a
139
-- message if no file was provided.
140
--
141
function config.process(file)
142
local cfg = {}
143
local comment_line_expr = "^%s*#.*"
144
-- We capture any whitespace padding here so we can easily advance to
145
-- the end of the line as needed to check for any trailing bogus bits.
146
-- Alternatively, we could drop the whitespace and instead try to
147
-- use a pattern to strip out the meaty part of the line, but then we
148
-- would need to sanitize the line for potentially special characters.
149
local line_expr = "^([%w%p]+%s*)=(%s*[`\"]?[^\"`]*[`\"]?)"
150
151
if not file then
152
return nil, "No file given"
153
end
154
155
local fh = assert(io.open(file))
156
157
for nextline in fh:lines() do
158
-- Strip any whole-line comments.
159
nextline = nextline:gsub(comment_line_expr, "")
160
-- Parse it into key, value pairs.
161
local key, value = nextline:match(line_expr)
162
if key ~= nil and value ~= nil then
163
local kvp = key .. "=" .. value
164
key = util.trim(key)
165
value = util.trim(value)
166
local delim = value:sub(1,1)
167
if delim == '"' then
168
local trailing_context
169
170
-- Strip off the key/value part.
171
trailing_context = nextline:sub(kvp:len() + 1)
172
-- Strip off any trailing comment.
173
trailing_context = trailing_context:gsub("#.*$",
174
"")
175
-- Strip off leading/trailing whitespace.
176
trailing_context = util.trim(trailing_context)
177
if trailing_context ~= "" then
178
print(trailing_context)
179
util.abort(1,
180
"Malformed line: " .. nextline)
181
end
182
183
value = util.trim(value, delim)
184
else
185
-- Strip off potential comments.
186
value = value:gsub("#.*$", "")
187
-- Strip off any padding whitespace.
188
value = util.trim(value)
189
if value:match("%s") then
190
util.abort(1,
191
"Malformed config line: " ..
192
nextline)
193
end
194
end
195
cfg[key] = value
196
elseif not nextline:match("^%s*$") then
197
-- Make sure format violations don't get overlooked
198
-- here, but ignore blank lines. Comments are already
199
-- stripped above.
200
util.abort(1, "Malformed config line: " .. nextline)
201
end
202
end
203
204
assert(fh:close())
205
return cfg
206
end
207
208
-- Merges processed configuration file into the global config map (see above),
209
-- or returns NIL and a message if no file was provided.
210
function config.merge(fh)
211
if not fh then
212
return nil, "No file given"
213
end
214
215
local res = assert(config.process(fh))
216
217
for k, v in pairs(res) do
218
if v ~= config[k] then
219
-- Handling of string lists:
220
if k:find("abi_flags") then
221
-- Match for pipe, that's how abi_flags
222
-- is formatted.
223
config[k] = util.setFromString(v, "[^|]+")
224
elseif k:find("syscall_abi_change") or
225
k:find("syscall_no_abi_change") or
226
k:find("obsol") or
227
k:find("unimpl") then
228
-- Match for space, that's how these
229
-- are formatted.
230
config[k] = util.setFromString(v, "[^ ]+")
231
else
232
config[k] = v
233
end
234
-- Construct config modified table as config
235
-- is processed.
236
config.modifications[k] = true
237
else
238
-- config wasn't modified.
239
config.modifications[k] = false
240
end
241
end
242
end
243
244
-- Returns TRUE if there are ABI changes from native for the provided ABI flag.
245
function config.abiChanges(name)
246
if config.known_abi_flags[name] == nil then
247
util.abort(1, "abi_changes: unknown flag: " .. name)
248
end
249
return config.abi_flags[name] ~= nil
250
end
251
252
-- Instantiates config.compat_options.
253
function config.mergeCompat()
254
if config.compat_set ~= "" then
255
if not compat_option_sets[config.compat_set] then
256
util.abort(1, "Undefined compat set: " ..
257
config.compat_set)
258
end
259
260
config.compat_options = compat_option_sets[config.compat_set]
261
end
262
end
263
264
return config
265
266