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