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