1 --
2 -- SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 --
4 -- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
5 --
6 -- Redistribution and use in source and binary forms, with or without
7 -- modification, are permitted provided that the following conditions
8 -- are met:
9 -- 1. Redistributions of source code must retain the above copyright
10 -- notice, this list of conditions and the following disclaimer.
11 -- 2. Redistributions in binary form must reproduce the above copyright
12 -- notice, this list of conditions and the following disclaimer in the
13 -- documentation and/or other materials provided with the distribution.
14 --
15 -- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 -- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 -- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 -- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 -- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 -- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 -- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 -- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 -- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 -- SUCH DAMAGE.
26 --
27 -- $FreeBSD$
28 --
29
30
31 -- We generally assume that this script will be run by flua, however we've
32 -- carefully crafted modules for it that mimic interfaces provided by modules
33 -- available in ports. Currently, this script is compatible with lua from ports
34 -- along with the compatible luafilesystem and lua-posix modules.
35 local lfs = require("lfs")
36 local unistd = require("posix.unistd")
37
38 local savesyscall = -1
39 local maxsyscall = -1
40 local generated_tag = "@" .. "generated"
41
42 -- Default configuration; any of these may get replaced by a configuration file
43 -- optionally specified.
44 local config = {
45 os_id_keyword = "FreeBSD",
46 abi_func_prefix = "",
47 sysnames = "syscalls.c",
48 sysproto = "../sys/sysproto.h",
49 sysproto_h = "_SYS_SYSPROTO_H_",
50 syshdr = "../sys/syscall.h",
51 sysmk = "../sys/syscall.mk",
52 syssw = "init_sysent.c",
53 syscallprefix = "SYS_",
54 switchname = "sysent",
55 namesname = "syscallnames",
56 systrace = "systrace_args.c",
57 capabilities_conf = "capabilities.conf",
58 capenabled = {},
59 compat_set = "native",
60 mincompat = 0,
61 abi_type_suffix = "",
62 abi_flags = "",
63 abi_flags_mask = 0,
64 abi_headers = "",
65 abi_intptr_t = "intptr_t",
66 abi_size_t = "size_t",
67 abi_u_long = "u_long",
68 abi_long = "long",
69 abi_semid_t = "semid_t",
70 abi_ptr_array_t = "",
71 ptr_intptr_t_cast = "intptr_t",
72 syscall_abi_change = "",
73 sys_abi_change = {},
74 syscall_no_abi_change = "",
75 sys_no_abi_change = {},
76 obsol = "",
77 obsol_dict = {},
78 unimpl = "",
79 unimpl_dict = {},
80 }
81
82 local config_modified = {}
83 local cleantmp = true
84 local tmpspace = "/tmp/sysent." .. unistd.getpid() .. "/"
85
86 local output_files = {
87 "sysnames",
88 "syshdr",
89 "sysmk",
90 "syssw",
91 "systrace",
92 "sysproto",
93 }
94
95 -- These ones we'll create temporary files for; generation purposes.
96 local temp_files = {
97 "sysaue",
98 "sysdcl",
99 "syscompat",
100 "syscompatdcl",
101 "sysent",
102 "sysinc",
103 "sysarg",
104 "sysprotoend",
105 "systracetmp",
106 "systraceret",
107 }
108
109 -- Opened files
110 local files = {}
111
112 local function cleanup()
113 for _, v in pairs(files) do
114 assert(v:close())
115 end
116 if cleantmp then
117 if lfs.dir(tmpspace) then
118 for fname in lfs.dir(tmpspace) do
119 if fname ~= "." and fname ~= ".." then
120 assert(os.remove(tmpspace .. "/" ..
121 fname))
122 end
123 end
124 end
125
126 if lfs.attributes(tmpspace) and not lfs.rmdir(tmpspace) then
127 assert(io.stderr:write("Failed to clean up tmpdir: " ..
128 tmpspace .. "\n"))
129 end
130 else
131 assert(io.stderr:write("Temp files left in " .. tmpspace ..
132 "\n"))
133 end
134 end
135
136 local function abort(status, msg)
137 assert(io.stderr:write(msg .. "\n"))
138 cleanup()
139 os.exit(status)
140 end
141
142 -- Each entry should have a value so we can represent abi flags as a bitmask
143 -- for convenience. One may also optionally provide an expr; this gets applied
144 -- to each argument type to indicate whether this argument is subject to ABI
145 -- change given the configured flags.
146 local known_abi_flags = {
147 long_size = {
148 value = 0x00000001,
149 exprs = {
150 "_Contains[a-z_]*_long_",
151 "^long [a-z0-9_]+$",
152 "long [*]",
153 "size_t [*]",
154 -- semid_t is not included because it is only used
155 -- as an argument or written out individually and
156 -- said writes are handled by the ksem framework.
157 -- Technically a sign-extension issue exists for
158 -- arguments, but because semid_t is actually a file
159 -- descriptor negative 32-bit values are invalid
160 -- regardless of sign-extension.
161 },
162 },
163 time_t_size = {
164 value = 0x00000002,
165 exprs = {
166 "_Contains[a-z_]*_timet_",
167 },
168 },
169 pointer_args = {
170 value = 0x00000004,
171 },
172 pointer_size = {
173 value = 0x00000008,
174 exprs = {
175 "_Contains[a-z_]*_ptr_",
176 "[*][*]",
177 },
178 },
179 pair_64bit = {
180 value = 0x00000010,
181 exprs = {
182 "^dev_t[ ]*$",
183 "^id_t[ ]*$",
184 "^off_t[ ]*$",
185 },
186 },
187 }
188
189 local known_flags = {
190 STD = 0x00000001,
191 OBSOL = 0x00000002,
192 RESERVED = 0x00000004,
193 UNIMPL = 0x00000008,
194 NODEF = 0x00000010,
195 NOARGS = 0x00000020,
196 NOPROTO = 0x00000040,
197 NOSTD = 0x00000080,
198 NOTSTATIC = 0x00000100,
199 CAPENABLED = 0x00000200,
200 SYSMUX = 0x00000400,
201
202 -- Compat flags start from here. We have plenty of space.
203 }
204
205 -- All compat option entries should have five entries:
206 -- definition: The preprocessor macro that will be set for this
207 -- compatlevel: The level this compatibility should be included at. This
208 -- generally represents the version of FreeBSD that it is compatible
209 -- with, but ultimately it's just the level of mincompat in which it's
210 -- included.
211 -- flag: The name of the flag in syscalls.master.
212 -- prefix: The prefix to use for _args and syscall prototype. This will be
213 -- used as-is, without "_" or any other character appended.
214 -- descr: The description of this compat option in init_sysent.c comments.
215 -- The special "stdcompat" entry will cause the other five to be autogenerated.
216 local compat_option_sets = {
217 native = {
218 {
219 definition = "COMPAT_43",
220 compatlevel = 3,
221 flag = "COMPAT",
222 prefix = "o",
223 descr = "old",
224 },
225 { stdcompat = "FREEBSD4" },
226 { stdcompat = "FREEBSD6" },
227 { stdcompat = "FREEBSD7" },
228 { stdcompat = "FREEBSD10" },
229 { stdcompat = "FREEBSD11" },
230 { stdcompat = "FREEBSD12" },
231 { stdcompat = "FREEBSD13" },
232 },
233 }
234
235 -- compat_options will be resolved to a set from the configuration.
236 local compat_options
237
238 local function trim(s, char)
239 if s == nil then
240 return nil
241 end
242 if char == nil then
243 char = "%s"
244 end
245 return s:gsub("^" .. char .. "+", ""):gsub(char .. "+$", "")
246 end
247
248 -- config looks like a shell script; in fact, the previous makesyscalls.sh
249 -- script actually sourced it in. It had a pretty common format, so we should
250 -- be fine to make various assumptions
251 local function process_config(file)
252 local cfg = {}
253 local comment_line_expr = "^%s*#.*"
254 -- We capture any whitespace padding here so we can easily advance to
255 -- the end of the line as needed to check for any trailing bogus bits.
256 -- Alternatively, we could drop the whitespace and instead try to
257 -- use a pattern to strip out the meaty part of the line, but then we
258 -- would need to sanitize the line for potentially special characters.
259 local line_expr = "^([%w%p]+%s*)=(%s*[`\"]?[^\"`]*[`\"]?)"
260
261 if not file then
262 return nil, "No file given"
263 end
264
265 local fh = assert(io.open(file))
266
267 for nextline in fh:lines() do
268 -- Strip any whole-line comments
269 nextline = nextline:gsub(comment_line_expr, "")
270 -- Parse it into key, value pairs
271 local key, value = nextline:match(line_expr)
272 if key ~= nil and value ~= nil then
273 local kvp = key .. "=" .. value
274 key = trim(key)
275 value = trim(value)
276 local delim = value:sub(1,1)
277 if delim == '"' then
278 local trailing_context
279
280 -- Strip off the key/value part
281 trailing_context = nextline:sub(kvp:len() + 1)
282 -- Strip off any trailing comment
283 trailing_context = trailing_context:gsub("#.*$",
284 "")
285 -- Strip off leading/trailing whitespace
286 trailing_context = trim(trailing_context)
287 if trailing_context ~= "" then
288 print(trailing_context)
289 abort(1, "Malformed line: " .. nextline)
290 end
291
292 value = trim(value, delim)
293 else
294 -- Strip off potential comments
295 value = value:gsub("#.*$", "")
296 -- Strip off any padding whitespace
297 value = trim(value)
298 if value:match("%s") then
299 abort(1, "Malformed config line: " ..
300 nextline)
301 end
302 end
303 cfg[key] = value
304 elseif not nextline:match("^%s*$") then
305 -- Make sure format violations don't get overlooked
306 -- here, but ignore blank lines. Comments are already
307 -- stripped above.
308 abort(1, "Malformed config line: " .. nextline)
309 end
310 end
311
312 assert(io.close(fh))
313 return cfg
314 end
315
316 local function grab_capenabled(file, open_fail_ok)
317 local capentries = {}
318 local commentExpr = "#.*"
319
320 if file == nil then
321 print "No file"
322 return {}
323 end
324
325 local fh = io.open(file)
326 if fh == nil then
327 if not open_fail_ok then
328 abort(1, "Failed to open " .. file)
329 end
330 return {}
331 end
332
333 for nextline in fh:lines() do
334 -- Strip any comments
335 nextline = nextline:gsub(commentExpr, "")
336 if nextline ~= "" then
337 capentries[nextline] = true
338 end
339 end
340
341 assert(io.close(fh))
342 return capentries
343 end
344
345 local function process_compat()
346 local nval = 0
347 for _, v in pairs(known_flags) do
348 if v > nval then
349 nval = v
350 end
351 end
352
353 nval = nval << 1
354 for _, v in pairs(compat_options) do
355 if v["stdcompat"] ~= nil then
356 local stdcompat = v["stdcompat"]
357 v["definition"] = "COMPAT_" .. stdcompat:upper()
358 v["compatlevel"] = tonumber(stdcompat:match("([0-9]+)$"))
359 v["flag"] = stdcompat:gsub("FREEBSD", "COMPAT")
360 v["prefix"] = stdcompat:lower() .. "_"
361 v["descr"] = stdcompat:lower()
362 end
363
364 local tmpname = "sys" .. v["flag"]:lower()
365 local dcltmpname = tmpname .. "dcl"
366 files[tmpname] = io.tmpfile()
367 files[dcltmpname] = io.tmpfile()
368 v["tmp"] = tmpname
369 v["dcltmp"] = dcltmpname
370
371 known_flags[v["flag"]] = nval
372 v["mask"] = nval
373 nval = nval << 1
374
375 v["count"] = 0
376 end
377 end
378
379 local function process_abi_flags()
380 local flags, mask = config["abi_flags"], 0
381 for txtflag in flags:gmatch("([^|]+)") do
382 if known_abi_flags[txtflag] == nil then
383 abort(1, "Unknown abi_flag: " .. txtflag)
384 end
385
386 mask = mask | known_abi_flags[txtflag]["value"]
387 end
388
389 config["abi_flags_mask"] = mask
390 end
391
392 local function process_obsol()
393 local obsol = config["obsol"]
394 for syscall in obsol:gmatch("([^ ]+)") do
395 config["obsol_dict"][syscall] = true
396 end
397 end
398
399 local function process_unimpl()
400 local unimpl = config["unimpl"]
401 for syscall in unimpl:gmatch("([^ ]+)") do
402 config["unimpl_dict"][syscall] = true
403 end
404 end
405
406 local function process_syscall_abi_change()
407 local changes_abi = config["syscall_abi_change"]
408 for syscall in changes_abi:gmatch("([^ ]+)") do
409 config["sys_abi_change"][syscall] = true
410 end
411
412 local no_changes = config["syscall_no_abi_change"]
413 for syscall in no_changes:gmatch("([^ ]+)") do
414 config["sys_no_abi_change"][syscall] = true
415 end
416 end
417
418 local function abi_changes(name)
419 if known_abi_flags[name] == nil then
420 abort(1, "abi_changes: unknown flag: " .. name)
421 end
422
423 return config["abi_flags_mask"] & known_abi_flags[name]["value"] ~= 0
424 end
425
426 local function strip_abi_prefix(funcname)
427 local abiprefix = config["abi_func_prefix"]
428 local stripped_name
429 if funcname == nil then
430 return nil
431 end
432 if abiprefix ~= "" and funcname:find("^" .. abiprefix) then
433 stripped_name = funcname:gsub("^" .. abiprefix, "")
434 else
435 stripped_name = funcname
436 end
437
438 return stripped_name
439 end
440
441 local function read_file(tmpfile)
442 if files[tmpfile] == nil then
443 print("Not found: " .. tmpfile)
444 return
445 end
446
447 local fh = files[tmpfile]
448 assert(fh:seek("set"))
449 return assert(fh:read("a"))
450 end
451
452 local function write_line(tmpfile, line)
453 if files[tmpfile] == nil then
454 print("Not found: " .. tmpfile)
455 return
456 end
457 assert(files[tmpfile]:write(line))
458 end
459
460 local function write_line_pfile(tmppat, line)
461 for k in pairs(files) do
462 if k:match(tmppat) ~= nil then
463 assert(files[k]:write(line))
464 end
465 end
466 end
467
468 -- Check both literal intptr_t and the abi version because this needs
469 -- to work both before and after the substitution
470 local function isptrtype(type)
471 return type:find("*") or type:find("caddr_t") or
472 type:find("intptr_t") or type:find(config['abi_intptr_t'])
473 end
474
475 local function isptrarraytype(type)
476 return type:find("[*][*]") or type:find("[*][ ]*const[ ]*[*]")
477 end
478
479 -- Find types that are always 64-bits wide
480 local function is64bittype(type)
481 return type:find("^dev_t[ ]*$") or type:find("^id_t[ ]*$") or type:find("^off_t[ ]*$")
482 end
483
484 local process_syscall_def
485
486 -- These patterns are processed in order on any line that isn't empty.
487 local pattern_table = {
488 {
489 pattern = "%s*$" .. config['os_id_keyword'],
490 process = function(_, _)
491 -- Ignore... ID tag
492 end,
493 },
494 {
495 dump_prevline = true,
496 pattern = "^#%s*include",
497 process = function(line)
498 line = line .. "\n"
499 write_line('sysinc', line)
500 end,
501 },
502 {
503 dump_prevline = true,
504 pattern = "^#",
505 process = function(line)
506 if line:find("^#%s*if") then
507 savesyscall = maxsyscall
508 elseif line:find("^#%s*else") then
509 maxsyscall = savesyscall
510 end
511 line = line .. "\n"
512 write_line('sysent', line)
513 write_line('sysdcl', line)
514 write_line('sysarg', line)
515 write_line_pfile('syscompat[0-9]*$', line)
516 write_line('sysnames', line)
517 write_line_pfile('systrace.*', line)
518 end,
519 },
520 {
521 dump_prevline = true,
522 pattern = "%%ABI_HEADERS%%",
523 process = function()
524 if config['abi_headers'] ~= "" then
525 line = config['abi_headers'] .. "\n"
526 write_line('sysinc', line)
527 end
528 end,
529 },
530 {
531 -- Buffer anything else
532 pattern = ".+",
533 process = function(line, prevline)
534 local incomplete = line:find("\\$") ~= nil
535 -- Lines that end in \ get the \ stripped
536 -- Lines that start with a syscall number, prepend \n
537 line = trim(line):gsub("\\$", "")
538 if line:find("^[0-9]") and prevline then
539 process_syscall_def(prevline)
540 prevline = nil
541 end
542
543 prevline = (prevline or '') .. line
544 incomplete = incomplete or prevline:find(",$") ~= nil
545 incomplete = incomplete or prevline:find("{") ~= nil and
546 prevline:find("}") == nil
547 if prevline:find("^[0-9]") and not incomplete then
548 process_syscall_def(prevline)
549 prevline = nil
550 end
551
552 return prevline
553 end,
554 },
555 }
556
557 local function process_sysfile(file)
558 local capentries = {}
559 local commentExpr = "^%s*;.*"
560
561 if file == nil then
562 print "No file"
563 return {}
564 end
565
566 local fh = io.open(file)
567 if fh == nil then
568 print("Failed to open " .. file)
569 return {}
570 end
571
572 local function do_match(nextline, prevline)
573 local pattern, handler, dump
574 for _, v in pairs(pattern_table) do
575 pattern = v['pattern']
576 handler = v['process']
577 dump = v['dump_prevline']
578 if nextline:match(pattern) then
579 if dump and prevline then
580 process_syscall_def(prevline)
581 prevline = nil
582 end
583
584 return handler(nextline, prevline)
585 end
586 end
587
588 abort(1, "Failed to handle: " .. nextline)
589 end
590
591 local prevline
592 for nextline in fh:lines() do
593 -- Strip any comments
594 nextline = nextline:gsub(commentExpr, "")
595 if nextline ~= "" then
596 prevline = do_match(nextline, prevline)
597 end
598 end
599
600 -- Dump any remainder
601 if prevline ~= nil and prevline:find("^[0-9]") then
602 process_syscall_def(prevline)
603 end
604
605 assert(io.close(fh))
606 return capentries
607 end
608
609 local function get_mask(flags)
610 local mask = 0
611 for _, v in ipairs(flags) do
612 if known_flags[v] == nil then
613 abort(1, "Checking for unknown flag " .. v)
614 end
615
616 mask = mask | known_flags[v]
617 end
618
619 return mask
620 end
621
622 local function get_mask_pat(pflags)
623 local mask = 0
624 for k, v in pairs(known_flags) do
625 if k:find(pflags) then
626 mask = mask | v
627 end
628 end
629
630 return mask
631 end
632
633 local function align_sysent_comment(col)
634 write_line("sysent", "\t")
635 col = col + 8 - col % 8
636 while col < 56 do
637 write_line("sysent", "\t")
638 col = col + 8
639 end
640 end
641
642 local function strip_arg_annotations(arg)
643 arg = arg:gsub("_Contains_[^ ]*[_)] ?", "")
644 arg = arg:gsub("_In[^ ]*[_)] ?", "")
645 arg = arg:gsub("_Out[^ ]*[_)] ?", "")
646 return trim(arg)
647 end
648
649 local function check_abi_changes(arg)
650 for k, v in pairs(known_abi_flags) do
651 local exprs = v["exprs"]
652 if abi_changes(k) and exprs ~= nil then
653 for _, e in pairs(exprs) do
654 if arg:find(e) then
655 return true
656 end
657 end
658 end
659 end
660
661 return false
662 end
663
664 local function process_args(args)
665 local funcargs = {}
666 local changes_abi = false
667
668 for arg in args:gmatch("([^,]+)") do
669 local arg_abi_change = check_abi_changes(arg)
670 changes_abi = changes_abi or arg_abi_change
671
672 arg = strip_arg_annotations(arg)
673
674 local argname = arg:match("([^* ]+)$")
675
676 -- argtype is... everything else.
677 local argtype = trim(arg:gsub(argname .. "$", ""), nil)
678
679 if argtype == "" and argname == "void" then
680 goto out
681 end
682
683 -- is64bittype() needs a bare type so check it after argname
684 -- is removed
685 changes_abi = changes_abi or (abi_changes("pair_64bit") and is64bittype(argtype))
686
687 argtype = argtype:gsub("intptr_t", config["abi_intptr_t"])
688 argtype = argtype:gsub("semid_t", config["abi_semid_t"])
689 if isptrtype(argtype) then
690 argtype = argtype:gsub("size_t", config["abi_size_t"])
691 argtype = argtype:gsub("^long", config["abi_long"]);
692 argtype = argtype:gsub("^u_long", config["abi_u_long"]);
693 argtype = argtype:gsub("^const u_long", "const " .. config["abi_u_long"]);
694 elseif argtype:find("^long$") then
695 argtype = config["abi_long"]
696 end
697 if isptrarraytype(argtype) and config["abi_ptr_array_t"] ~= "" then
698 -- `* const *` -> `**`
699 argtype = argtype:gsub("[*][ ]*const[ ]*[*]", "**")
700 -- e.g., `struct aiocb **` -> `uint32_t *`
701 argtype = argtype:gsub("[^*]*[*]", config["abi_ptr_array_t"] .. " ", 1)
702 end
703
704 -- XX TODO: Forward declarations? See: sysstubfwd in CheriBSD
705 if arg_abi_change then
706 local abi_type_suffix = config["abi_type_suffix"]
707 argtype = argtype:gsub("(struct [^ ]*)", "%1" ..
708 abi_type_suffix)
709 argtype = argtype:gsub("(union [^ ]*)", "%1" ..
710 abi_type_suffix)
711 end
712
713 if abi_changes("pair_64bit") and is64bittype(argtype) then
714 if #funcargs % 2 == 1 then
715 funcargs[#funcargs + 1] = {
716 type = "int",
717 name = "_pad",
718 }
719 end
720 funcargs[#funcargs + 1] = {
721 type = "uint32_t",
722 name = argname .. "1",
723 }
724 funcargs[#funcargs + 1] = {
725 type = "uint32_t",
726 name = argname .. "2",
727 }
728 else
729 funcargs[#funcargs + 1] = {
730 type = argtype,
731 name = argname,
732 }
733 end
734 end
735
736 ::out::
737 return funcargs, changes_abi
738 end
739
740 local function handle_noncompat(sysnum, thr_flag, flags, sysflags, rettype,
741 auditev, syscallret, funcname, funcalias, funcargs, argalias)
742 local argssize
743
744 if flags & known_flags["SYSMUX"] ~= 0 then
745 argssize = "0"
746 elseif #funcargs > 0 or flags & known_flags["NODEF"] ~= 0 then
747 argssize = "AS(" .. argalias .. ")"
748 else
749 argssize = "0"
750 end
751
752 write_line("systrace", string.format([[
753 /* %s */
754 case %d: {
755 ]], funcname, sysnum))
756 write_line("systracetmp", string.format([[
757 /* %s */
758 case %d:
759 ]], funcname, sysnum))
760 write_line("systraceret", string.format([[
761 /* %s */
762 case %d:
763 ]], funcname, sysnum))
764
765 if #funcargs > 0 and flags & known_flags["SYSMUX"] == 0 then
766 write_line("systracetmp", "\t\tswitch (ndx) {\n")
767 write_line("systrace", string.format(
768 "\t\tstruct %s *p = params;\n", argalias))
769
770
771 local argtype, argname, desc, padding
772 padding = ""
773 for idx, arg in ipairs(funcargs) do
774 argtype = arg["type"]
775 argname = arg["name"]
776
777 argtype = trim(argtype:gsub("__restrict$", ""), nil)
778 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
779 write_line("systracetmp", "#ifdef PAD64_REQUIRED\n")
780 end
781 -- Pointer arg?
782 if argtype:find("*") then
783 desc = "userland " .. argtype
784 else
785 desc = argtype;
786 end
787 write_line("systracetmp", string.format(
788 "\t\tcase %d%s:\n\t\t\tp = \"%s\";\n\t\t\tbreak;\n",
789 idx - 1, padding, desc))
790 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
791 padding = " - _P_"
792 write_line("systracetmp", "#define _P_ 0\n#else\n#define _P_ 1\n#endif\n")
793 end
794
795 if isptrtype(argtype) then
796 write_line("systrace", string.format(
797 "\t\tuarg[a++] = (%s)p->%s; /* %s */\n",
798 config["ptr_intptr_t_cast"],
799 argname, argtype))
800 elseif argtype == "union l_semun" then
801 write_line("systrace", string.format(
802 "\t\tuarg[a++] = p->%s.buf; /* %s */\n",
803 argname, argtype))
804 elseif argtype:sub(1,1) == "u" or argtype == "size_t" then
805 write_line("systrace", string.format(
806 "\t\tuarg[a++] = p->%s; /* %s */\n",
807 argname, argtype))
808 else
809 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
810 write_line("systrace", "#ifdef PAD64_REQUIRED\n")
811 end
812 write_line("systrace", string.format(
813 "\t\tiarg[a++] = p->%s; /* %s */\n",
814 argname, argtype))
815 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
816 write_line("systrace", "#endif\n")
817 end
818 end
819 end
820
821 write_line("systracetmp",
822 "\t\tdefault:\n\t\t\tbreak;\n\t\t};\n")
823 if padding ~= "" then
824 write_line("systracetmp", "#undef _P_\n\n")
825 end
826
827 write_line("systraceret", string.format([[
828 if (ndx == 0 || ndx == 1)
829 p = "%s";
830 break;
831 ]], syscallret))
832 end
833 local n_args = #funcargs
834 if flags & known_flags["SYSMUX"] ~= 0 then
835 n_args = 0
836 end
837 write_line("systrace", string.format(
838 "\t\t*n_args = %d;\n\t\tbreak;\n\t}\n", n_args))
839 write_line("systracetmp", "\t\tbreak;\n")
840
841 local nargflags = get_mask({"NOARGS", "NOPROTO", "NODEF"})
842 if flags & nargflags == 0 then
843 if #funcargs > 0 then
844 write_line("sysarg", string.format("struct %s {\n",
845 argalias))
846 for _, v in ipairs(funcargs) do
847 local argname, argtype = v["name"], v["type"]
848 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
849 write_line("sysarg", "#ifdef PAD64_REQUIRED\n")
850 end
851 write_line("sysarg", string.format(
852 "\tchar %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];\n",
853 argname, argtype,
854 argtype, argname,
855 argname, argtype))
856 if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
857 write_line("sysarg", "#endif\n")
858 end
859 end
860 write_line("sysarg", "};\n")
861 else
862 write_line("sysarg", string.format(
863 "struct %s {\n\tsyscallarg_t dummy;\n};\n", argalias))
864 end
865 end
866
867 local protoflags = get_mask({"NOPROTO", "NODEF"})
868 if flags & protoflags == 0 then
869 if funcname == "nosys" or funcname == "lkmnosys" or
870 funcname == "sysarch" or funcname:find("^freebsd") or
871 funcname:find("^linux") then
872 write_line("sysdcl", string.format(
873 "%s\t%s(struct thread *, struct %s *)",
874 rettype, funcname, argalias))
875 else
876 write_line("sysdcl", string.format(
877 "%s\tsys_%s(struct thread *, struct %s *)",
878 rettype, funcname, argalias))
879 end
880 write_line("sysdcl", ";\n")
881 write_line("sysaue", string.format("#define\t%sAUE_%s\t%s\n",
882 config['syscallprefix'], funcalias, auditev))
883 end
884
885 write_line("sysent",
886 string.format("\t{ .sy_narg = %s, .sy_call = (sy_call_t *)", argssize))
887 local column = 8 + 2 + #argssize + 15
888
889 if flags & known_flags["SYSMUX"] ~= 0 then
890 write_line("sysent", string.format(
891 "nosys, .sy_auevent = AUE_NULL, " ..
892 ".sy_flags = %s, .sy_thrcnt = SY_THR_STATIC },",
893 sysflags))
894 column = column + #"nosys" + #"AUE_NULL" + 3
895 elseif flags & known_flags["NOSTD"] ~= 0 then
896 write_line("sysent", string.format(
897 "lkmressys, .sy_auevent = AUE_NULL, " ..
898 ".sy_flags = %s, .sy_thrcnt = SY_THR_ABSENT },",
899 sysflags))
900 column = column + #"lkmressys" + #"AUE_NULL" + 3
901 else
902 if funcname == "nosys" or funcname == "lkmnosys" or
903 funcname == "sysarch" or funcname:find("^freebsd") or
904 funcname:find("^linux") then
905 write_line("sysent", string.format(
906 "%s, .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
907 funcname, auditev, sysflags, thr_flag))
908 column = column + #funcname + #auditev + #sysflags + 3
909 else
910 write_line("sysent", string.format(
911 "sys_%s, .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
912 funcname, auditev, sysflags, thr_flag))
913 column = column + #funcname + #auditev + #sysflags + 7
914 end
915 end
916
917 align_sysent_comment(column)
918 write_line("sysent", string.format("/* %d = %s */\n",
919 sysnum, funcalias))
920 write_line("sysnames", string.format("\t\"%s\",\t\t\t/* %d = %s */\n",
921 funcalias, sysnum, funcalias))
922
923 if flags & known_flags["NODEF"] == 0 then
924 write_line("syshdr", string.format("#define\t%s%s\t%d\n",
925 config['syscallprefix'], funcalias, sysnum))
926 write_line("sysmk", string.format(" \\\n\t%s.o",
927 funcalias))
928 end
929 end
930
931 local function handle_obsol(sysnum, funcname, comment)
932 write_line("sysent",
933 "\t{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, " ..
934 ".sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },")
935 align_sysent_comment(34)
936
937 write_line("sysent", string.format("/* %d = obsolete %s */\n",
938 sysnum, comment))
939 write_line("sysnames", string.format(
940 "\t\"obs_%s\",\t\t\t/* %d = obsolete %s */\n",
941 funcname, sysnum, comment))
942 write_line("syshdr", string.format("\t\t\t\t/* %d is obsolete %s */\n",
943 sysnum, comment))
944 end
945
946 local function handle_compat(sysnum, thr_flag, flags, sysflags, rettype,
947 auditev, funcname, funcalias, funcargs, argalias)
948 local argssize, out, outdcl, wrap, prefix, descr
949
950 if #funcargs > 0 or flags & known_flags["NODEF"] ~= 0 then
951 argssize = "AS(" .. argalias .. ")"
952 else
953 argssize = "0"
954 end
955
956 for _, v in pairs(compat_options) do
957 if flags & v["mask"] ~= 0 then
958 if config["mincompat"] > v["compatlevel"] then
959 funcname = strip_abi_prefix(funcname)
960 funcname = v["prefix"] .. funcname
961 return handle_obsol(sysnum, funcname, funcname)
962 end
963 v["count"] = v["count"] + 1
964 out = v["tmp"]
965 outdcl = v["dcltmp"]
966 wrap = v["flag"]:lower()
967 prefix = v["prefix"]
968 descr = v["descr"]
969 goto compatdone
970 end
971 end
972
973 ::compatdone::
974 local dprotoflags = get_mask({"NOPROTO", "NODEF"})
975 local nargflags = dprotoflags | known_flags["NOARGS"]
976 if #funcargs > 0 and flags & nargflags == 0 then
977 write_line(out, string.format("struct %s {\n", argalias))
978 for _, v in ipairs(funcargs) do
979 local argname, argtype = v["name"], v["type"]
980 write_line(out, string.format(
981 "\tchar %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];\n",
982 argname, argtype,
983 argtype, argname,
984 argname, argtype))
985 end
986 write_line(out, "};\n")
987 elseif flags & nargflags == 0 then
988 write_line("sysarg", string.format(
989 "struct %s {\n\tsyscallarg_t dummy;\n};\n", argalias))
990 end
991 if flags & dprotoflags == 0 then
992 write_line(outdcl, string.format(
993 "%s\t%s%s(struct thread *, struct %s *);\n",
994 rettype, prefix, funcname, argalias))
995 write_line("sysaue", string.format(
996 "#define\t%sAUE_%s%s\t%s\n", config['syscallprefix'],
997 prefix, funcname, auditev))
998 end
999
1000 if flags & known_flags['NOSTD'] ~= 0 then
1001 write_line("sysent", string.format(
1002 "\t{ .sy_narg = %s, .sy_call = (sy_call_t *)%s, " ..
1003 ".sy_auevent = %s, .sy_flags = 0, " ..
1004 ".sy_thrcnt = SY_THR_ABSENT },",
1005 "0", "lkmressys", "AUE_NULL"))
1006 align_sysent_comment(8 + 2 + #"0" + 15 + #"lkmressys" +
1007 #"AUE_NULL" + 3)
1008 else
1009 write_line("sysent", string.format(
1010 "\t{ %s(%s,%s), .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
1011 wrap, argssize, funcname, auditev, sysflags, thr_flag))
1012 align_sysent_comment(8 + 9 + #argssize + 1 + #funcname +
1013 #auditev + #sysflags + 4)
1014 end
1015
1016 write_line("sysent", string.format("/* %d = %s %s */\n",
1017 sysnum, descr, funcalias))
1018 write_line("sysnames", string.format(
1019 "\t\"%s.%s\",\t\t/* %d = %s %s */\n",
1020 wrap, funcalias, sysnum, descr, funcalias))
1021 -- Do not provide freebsdN_* symbols in libc for < FreeBSD 7
1022 local nosymflags = get_mask({"COMPAT", "COMPAT4", "COMPAT6"})
1023 if flags & nosymflags ~= 0 then
1024 write_line("syshdr", string.format(
1025 "\t\t\t\t/* %d is %s %s */\n",
1026 sysnum, descr, funcalias))
1027 elseif flags & known_flags["NODEF"] == 0 then
1028 write_line("syshdr", string.format("#define\t%s%s%s\t%d\n",
1029 config['syscallprefix'], prefix, funcalias, sysnum))
1030 write_line("sysmk", string.format(" \\\n\t%s%s.o",
1031 prefix, funcalias))
1032 end
1033 end
1034
1035 local function handle_unimpl(sysnum, sysstart, sysend, comment)
1036 if sysstart == nil and sysend == nil then
1037 sysstart = tonumber(sysnum)
1038 sysend = tonumber(sysnum)
1039 end
1040
1041 sysnum = sysstart
1042 while sysnum <= sysend do
1043 write_line("sysent", string.format(
1044 "\t{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, " ..
1045 ".sy_auevent = AUE_NULL, .sy_flags = 0, " ..
1046 ".sy_thrcnt = SY_THR_ABSENT },\t\t\t/* %d = %s */\n",
1047 sysnum, comment))
1048 write_line("sysnames", string.format(
1049 "\t\"#%d\",\t\t\t/* %d = %s */\n",
1050 sysnum, sysnum, comment))
1051 sysnum = sysnum + 1
1052 end
1053 end
1054
1055 local function handle_reserved(sysnum, sysstart, sysend, comment)
1056 handle_unimpl(sysnum, sysstart, sysend, "reserved for local use")
1057 end
1058
1059 process_syscall_def = function(line)
1060 local sysstart, sysend, flags, funcname, sysflags
1061 local thr_flag, syscallret
1062 local orig = line
1063 flags = 0
1064 thr_flag = "SY_THR_STATIC"
1065
1066 -- Parse out the interesting information first
1067 local initialExpr = "^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s*"
1068 local sysnum, auditev, allflags = line:match(initialExpr)
1069
1070 if sysnum == nil or auditev == nil or allflags == nil then
1071 -- XXX TODO: Better?
1072 abort(1, "Completely malformed: " .. line)
1073 end
1074
1075 if sysnum:find("-") then
1076 sysstart, sysend = sysnum:match("^([%d]+)-([%d]+)$")
1077 if sysstart == nil or sysend == nil then
1078 abort(1, "Malformed range: " .. sysnum)
1079 end
1080 sysnum = nil
1081 sysstart = tonumber(sysstart)
1082 sysend = tonumber(sysend)
1083 if sysstart ~= maxsyscall + 1 then
1084 abort(1, "syscall number out of sync, missing " ..
1085 maxsyscall + 1)
1086 end
1087 else
1088 sysnum = tonumber(sysnum)
1089 if sysnum ~= maxsyscall + 1 then
1090 abort(1, "syscall number out of sync, missing " ..
1091 maxsyscall + 1)
1092 end
1093 end
1094
1095 -- Split flags
1096 for flag in allflags:gmatch("([^|]+)") do
1097 if known_flags[flag] == nil then
1098 abort(1, "Unknown flag " .. flag .. " for " .. sysnum)
1099 end
1100 flags = flags | known_flags[flag]
1101 end
1102
1103 if (flags & get_mask({"RESERVED", "UNIMPL"})) == 0 and sysnum == nil then
1104 abort(1, "Range only allowed with RESERVED and UNIMPL: " .. line)
1105 end
1106
1107 if (flags & known_flags["NOTSTATIC"]) ~= 0 then
1108 thr_flag = "SY_THR_ABSENT"
1109 end
1110
1111 -- Strip earlier bits out, leave declaration + alt
1112 line = line:gsub("^.+" .. allflags .. "%s*", "")
1113
1114 local decl_fnd = line:find("^{") ~= nil
1115 if decl_fnd and line:find("}") == nil then
1116 abort(1, "Malformed, no closing brace: " .. line)
1117 end
1118
1119 local decl, alt
1120 if decl_fnd then
1121 line = line:gsub("^{", "")
1122 decl, alt = line:match("([^}]*)}[%s]*(.*)$")
1123 else
1124 alt = line
1125 end
1126
1127 if decl == nil and alt == nil then
1128 abort(1, "Malformed bits: " .. line)
1129 end
1130
1131 local funcalias, funcomment, argalias, rettype, args
1132 if not decl_fnd and alt ~= nil and alt ~= "" then
1133 -- Peel off one entry for name
1134 funcname = trim(alt:match("^([^%s]+)"), nil)
1135 alt = alt:gsub("^([^%s]+)[%s]*", "")
1136 end
1137 -- Do we even need it?
1138 if flags & get_mask({"OBSOL", "UNIMPL"}) ~= 0 then
1139 local NF = 0
1140 for _ in orig:gmatch("[^%s]+") do
1141 NF = NF + 1
1142 end
1143
1144 funcomment = funcname or ''
1145 if NF < 6 then
1146 funcomment = funcomment .. " " .. alt
1147 end
1148
1149 funcomment = trim(funcomment)
1150
1151 -- if funcname ~= nil then
1152 -- else
1153 -- funcomment = trim(alt)
1154 -- end
1155 goto skipalt
1156 end
1157
1158 if alt ~= nil and alt ~= "" then
1159 local altExpr = "^([^%s]+)%s+([^%s]+)%s+([^%s]+)"
1160 funcalias, argalias, rettype = alt:match(altExpr)
1161 funcalias = trim(funcalias)
1162 if funcalias == nil or argalias == nil or rettype == nil then
1163 abort(1, "Malformed alt: " .. line)
1164 end
1165 end
1166 if decl_fnd then
1167 -- Don't clobber rettype set in the alt information
1168 if rettype == nil then
1169 rettype = "int"
1170 end
1171 -- Peel off the return type
1172 syscallret = line:match("([^%s]+)%s")
1173 line = line:match("[^%s]+%s(.+)")
1174 -- Pointer incoming
1175 if line:sub(1,1) == "*" then
1176 syscallret = syscallret .. " "
1177 end
1178 while line:sub(1,1) == "*" do
1179 line = line:sub(2)
1180 syscallret = syscallret .. "*"
1181 end
1182 funcname = line:match("^([^(]+)%(")
1183 if funcname == nil then
1184 abort(1, "Not a signature? " .. line)
1185 end
1186 args = line:match("^[^(]+%((.+)%)[^)]*$")
1187 args = trim(args, '[,%s]')
1188 end
1189
1190 ::skipalt::
1191
1192 if funcname == nil then
1193 funcname = funcalias
1194 end
1195
1196 funcname = trim(funcname)
1197
1198 if config["obsol_dict"][funcname] then
1199 local compat_prefix = ""
1200 for _, v in pairs(compat_options) do
1201 if flags & v["mask"] ~= 0 then
1202 compat_prefix = v["prefix"]
1203 goto obsol_compat_done
1204 end
1205 end
1206 ::obsol_compat_done::
1207 args = nil
1208 flags = known_flags['OBSOL']
1209 funcomment = compat_prefix .. funcname
1210 end
1211 if config["unimpl_dict"][funcname] then
1212 flags = known_flags['UNIMPL']
1213 funcomment = funcname
1214 end
1215
1216 sysflags = "0"
1217
1218 -- NODEF events do not get audited
1219 if flags & known_flags['NODEF'] ~= 0 then
1220 auditev = 'AUE_NULL'
1221 end
1222
1223 -- If applicable; strip the ABI prefix from the name
1224 local stripped_name = strip_abi_prefix(funcname)
1225
1226 if flags & known_flags['CAPENABLED'] ~= 0 or
1227 config["capenabled"][funcname] ~= nil or
1228 config["capenabled"][stripped_name] ~= nil then
1229 sysflags = "SYF_CAPENABLED"
1230 end
1231
1232 local funcargs = {}
1233 local changes_abi = false
1234 if args ~= nil then
1235 funcargs, changes_abi = process_args(args)
1236 end
1237 if config["sys_no_abi_change"][funcname] then
1238 changes_abi = false
1239 end
1240 local noproto = config["abi_flags"] ~= "" and not changes_abi
1241
1242 local argprefix = ''
1243 local funcprefix = ''
1244 if abi_changes("pointer_args") then
1245 for _, v in ipairs(funcargs) do
1246 if isptrtype(v["type"]) then
1247 if config["sys_no_abi_change"][funcname] then
1248 print("WARNING: " .. funcname ..
1249 " in syscall_no_abi_change, but pointers args are present")
1250 end
1251 changes_abi = true
1252 goto ptrfound
1253 end
1254 end
1255 ::ptrfound::
1256 end
1257 if config["sys_abi_change"][funcname] then
1258 changes_abi = true
1259 end
1260 if changes_abi then
1261 -- argalias should be:
1262 -- COMPAT_PREFIX + ABI Prefix + funcname
1263 argprefix = config['abi_func_prefix']
1264 funcprefix = config['abi_func_prefix']
1265 funcalias = funcprefix .. funcname
1266 noproto = false
1267 end
1268 if funcname ~= nil then
1269 funcname = funcprefix .. funcname
1270 end
1271 if funcalias == nil or funcalias == "" then
1272 funcalias = funcname
1273 end
1274
1275 if argalias == nil and funcname ~= nil then
1276 argalias = funcname .. "_args"
1277 for _, v in pairs(compat_options) do
1278 local mask = v["mask"]
1279 if (flags & mask) ~= 0 then
1280 -- Multiple aliases doesn't seem to make
1281 -- sense.
1282 argalias = v["prefix"] .. argalias
1283 goto out
1284 end
1285 end
1286 ::out::
1287 elseif argalias ~= nil then
1288 argalias = argprefix .. argalias
1289 end
1290
1291 local ncompatflags = get_mask({"STD", "NODEF", "NOARGS", "NOPROTO",
1292 "NOSTD"})
1293 local compatflags = get_mask_pat("COMPAT.*")
1294 if noproto or flags & known_flags["SYSMUX"] ~= 0 then
1295 flags = flags | known_flags["NOPROTO"];
1296 end
1297 if flags & known_flags["OBSOL"] ~= 0 then
1298 handle_obsol(sysnum, funcname, funcomment)
1299 elseif flags & known_flags["RESERVED"] ~= 0 then
1300 handle_reserved(sysnum, sysstart, sysend)
1301 elseif flags & known_flags["UNIMPL"] ~= 0 then
1302 handle_unimpl(sysnum, sysstart, sysend, funcomment)
1303 elseif flags & compatflags ~= 0 then
1304 if flags & known_flags['STD'] ~= 0 then
1305 abort(1, "Incompatible COMPAT/STD: " .. line)
1306 end
1307 handle_compat(sysnum, thr_flag, flags, sysflags, rettype,
1308 auditev, funcname, funcalias, funcargs, argalias)
1309 elseif flags & ncompatflags ~= 0 then
1310 handle_noncompat(sysnum, thr_flag, flags, sysflags, rettype,
1311 auditev, syscallret, funcname, funcalias, funcargs,
1312 argalias)
1313 else
1314 abort(1, "Bad flags? " .. line)
1315 end
1316
1317 if sysend ~= nil then
1318 maxsyscall = sysend
1319 elseif sysnum ~= nil then
1320 maxsyscall = sysnum
1321 end
1322 end
1323
1324 -- Entry point
1325
1326 if #arg < 1 or #arg > 2 then
1327 error("usage: " .. arg[0] .. " input-file <config-file>")
1328 end
1329
1330 local sysfile, configfile = arg[1], arg[2]
1331
1332 -- process_config either returns nil and a message, or a
1333 -- table that we should merge into the global config
1334 if configfile ~= nil then
1335 local res = assert(process_config(configfile))
1336
1337 for k, v in pairs(res) do
1338 if v ~= config[k] then
1339 config[k] = v
1340 config_modified[k] = true
1341 end
1342 end
1343 end
1344
1345 local compat_set = config['compat_set']
1346 if compat_set ~= "" then
1347 if not compat_option_sets[compat_set] then
1348 abort(1, "Undefined compat set: " .. compat_set)
1349 end
1350
1351 compat_options = compat_option_sets[compat_set]
1352 else
1353 compat_options = {}
1354 end
1355
1356 -- We ignore errors here if we're relying on the default configuration.
1357 if not config_modified["capenabled"] then
1358 config["capenabled"] = grab_capenabled(config['capabilities_conf'],
1359 config_modified["capabilities_conf"] == nil)
1360 elseif config["capenabled"] ~= "" then
1361 -- Due to limitations in the config format mostly, we'll have a comma
1362 -- separated list. Parse it into lines
1363 local capenabled = {}
1364 -- print("here: " .. config["capenabled"])
1365 for sysc in config["capenabled"]:gmatch("([^,]+)") do
1366 capenabled[sysc] = true
1367 end
1368 config["capenabled"] = capenabled
1369 end
1370 process_compat()
1371 process_abi_flags()
1372 process_syscall_abi_change()
1373 process_obsol()
1374 process_unimpl()
1375
1376 if not lfs.mkdir(tmpspace) then
1377 error("Failed to create tempdir " .. tmpspace)
1378 end
1379
1380 -- XXX Revisit the error handling here, we should probably move the rest of this
1381 -- into a function that we pcall() so we can catch the errors and clean up
1382 -- gracefully.
1383 for _, v in ipairs(temp_files) do
1384 local tmpname = tmpspace .. v
1385 files[v] = io.open(tmpname, "w+")
1386 -- XXX Revisit these with a pcall() + error handler
1387 if not files[v] then
1388 abort(1, "Failed to open temp file: " .. tmpname)
1389 end
1390 end
1391
1392 for _, v in ipairs(output_files) do
1393 local tmpname = tmpspace .. v
1394 files[v] = io.open(tmpname, "w+")
1395 -- XXX Revisit these with a pcall() + error handler
1396 if not files[v] then
1397 abort(1, "Failed to open temp output file: " .. tmpname)
1398 end
1399 end
1400
1401 -- Write out all of the preamble bits
1402 write_line("sysent", string.format([[
1403
1404 /* The casts are bogus but will do for now. */
1405 struct sysent %s[] = {
1406 ]], config['switchname']))
1407
1408 write_line("syssw", string.format([[/*
1409 * System call switch table.
1410 *
1411 * DO NOT EDIT-- this file is automatically %s.
1412 * $%s$
1413 */
1414
1415 ]], generated_tag, config['os_id_keyword']))
1416
1417 write_line("sysarg", string.format([[/*
1418 * System call prototypes.
1419 *
1420 * DO NOT EDIT-- this file is automatically %s.
1421 * $%s$
1422 */
1423
1424 #ifndef %s
1425 #define %s
1426
1427 #include <sys/signal.h>
1428 #include <sys/acl.h>
1429 #include <sys/cpuset.h>
1430 #include <sys/domainset.h>
1431 #include <sys/_ffcounter.h>
1432 #include <sys/_semaphore.h>
1433 #include <sys/ucontext.h>
1434 #include <sys/wait.h>
1435
1436 #include <bsm/audit_kevents.h>
1437
1438 struct proc;
1439
1440 struct thread;
1441
1442 #define PAD_(t) (sizeof(syscallarg_t) <= sizeof(t) ? \
1443 0 : sizeof(syscallarg_t) - sizeof(t))
1444
1445 #if BYTE_ORDER == LITTLE_ENDIAN
1446 #define PADL_(t) 0
1447 #define PADR_(t) PAD_(t)
1448 #else
1449 #define PADL_(t) PAD_(t)
1450 #define PADR_(t) 0
1451 #endif
1452
1453 ]], generated_tag, config['os_id_keyword'], config['sysproto_h'],
1454 config['sysproto_h']))
1455 if abi_changes("pair_64bit") then
1456 write_line("sysarg", string.format([[
1457 #if !defined(PAD64_REQUIRED) && !defined(__amd64__)
1458 #define PAD64_REQUIRED
1459 #endif
1460 ]]))
1461 end
1462 if abi_changes("pair_64bit") then
1463 write_line("systrace", string.format([[
1464 #if !defined(PAD64_REQUIRED) && !defined(__amd64__)
1465 #define PAD64_REQUIRED
1466 #endif
1467 ]]))
1468 end
1469 for _, v in pairs(compat_options) do
1470 write_line(v["tmp"], string.format("\n#ifdef %s\n\n", v["definition"]))
1471 end
1472
1473 write_line("sysnames", string.format([[/*
1474 * System call names.
1475 *
1476 * DO NOT EDIT-- this file is automatically %s.
1477 * $%s$
1478 */
1479
1480 const char *%s[] = {
1481 ]], generated_tag, config['os_id_keyword'], config['namesname']))
1482
1483 write_line("syshdr", string.format([[/*
1484 * System call numbers.
1485 *
1486 * DO NOT EDIT-- this file is automatically %s.
1487 * $%s$
1488 */
1489
1490 ]], generated_tag, config['os_id_keyword']))
1491
1492 write_line("sysmk", string.format([[# FreeBSD system call object files.
1493 # DO NOT EDIT-- this file is automatically %s.
1494 # $%s$
1495 MIASM = ]], generated_tag, config['os_id_keyword']))
1496
1497 write_line("systrace", string.format([[/*
1498 * System call argument to DTrace register array converstion.
1499 *
1500 * DO NOT EDIT-- this file is automatically %s.
1501 * $%s$
1502 * This file is part of the DTrace syscall provider.
1503 */
1504
1505 static void
1506 systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
1507 {
1508 int64_t *iarg = (int64_t *)uarg;
1509 int a = 0;
1510 switch (sysnum) {
1511 ]], generated_tag, config['os_id_keyword']))
1512
1513 write_line("systracetmp", [[static void
1514 systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
1515 {
1516 const char *p = NULL;
1517 switch (sysnum) {
1518 ]])
1519
1520 write_line("systraceret", [[static void
1521 systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
1522 {
1523 const char *p = NULL;
1524 switch (sysnum) {
1525 ]])
1526
1527 -- Processing the sysfile will parse out the preprocessor bits and put them into
1528 -- the appropriate place. Any syscall-looking lines get thrown into the sysfile
1529 -- buffer, one per line, for later processing once they're all glued together.
1530 process_sysfile(sysfile)
1531
1532 write_line("sysinc",
1533 "\n#define AS(name) (sizeof(struct name) / sizeof(syscallarg_t))\n")
1534
1535 for _, v in pairs(compat_options) do
1536 if v["count"] > 0 then
1537 write_line("sysinc", string.format([[
1538
1539 #ifdef %s
1540 #define %s(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(%s, name)
1541 #else
1542 #define %s(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
1543 #endif
1544 ]], v["definition"], v["flag"]:lower(), v["prefix"], v["flag"]:lower()))
1545 end
1546
1547 write_line(v["dcltmp"], string.format("\n#endif /* %s */\n\n",
1548 v["definition"]))
1549 end
1550
1551 write_line("sysprotoend", string.format([[
1552
1553 #undef PAD_
1554 #undef PADL_
1555 #undef PADR_
1556
1557 #endif /* !%s */
1558 ]], config["sysproto_h"]))
1559
1560 write_line("sysmk", "\n")
1561 write_line("sysent", "};\n")
1562 write_line("sysnames", "};\n")
1563 -- maxsyscall is the highest seen; MAXSYSCALL should be one higher
1564 write_line("syshdr", string.format("#define\t%sMAXSYSCALL\t%d\n",
1565 config["syscallprefix"], maxsyscall + 1))
1566 write_line("systrace", [[
1567 default:
1568 *n_args = 0;
1569 break;
1570 };
1571 }
1572 ]])
1573
1574 write_line("systracetmp", [[
1575 default:
1576 break;
1577 };
1578 if (p != NULL)
1579 strlcpy(desc, p, descsz);
1580 }
1581 ]])
1582
1583 write_line("systraceret", [[
1584 default:
1585 break;
1586 };
1587 if (p != NULL)
1588 strlcpy(desc, p, descsz);
1589 }
1590 ]])
1591
1592 -- Finish up; output
1593 write_line("syssw", read_file("sysinc"))
1594 write_line("syssw", read_file("sysent"))
1595
1596 write_line("sysproto", read_file("sysarg"))
1597 write_line("sysproto", read_file("sysdcl"))
1598 for _, v in pairs(compat_options) do
1599 write_line("sysproto", read_file(v["tmp"]))
1600 write_line("sysproto", read_file(v["dcltmp"]))
1601 end
1602 write_line("sysproto", read_file("sysaue"))
1603 write_line("sysproto", read_file("sysprotoend"))
1604
1605 write_line("systrace", read_file("systracetmp"))
1606 write_line("systrace", read_file("systraceret"))
1607
1608 for _, v in ipairs(output_files) do
1609 local target = config[v]
1610 if target ~= "/dev/null" then
1611 local fh = assert(io.open(target, "w+"))
1612 if fh == nil then
1613 abort(1, "Failed to open '" .. target .. "'")
1614 end
1615 assert(fh:write(read_file(v)))
1616 assert(fh:close())
1617 end
1618 end
1619
1620 cleanup()
Cache object: 1a4b6a5cfc5686df3f35b19bfd206649
|