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