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