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