aboutsummaryrefslogblamecommitdiff
path: root/sys/tools/makesyscalls.lua
blob: 393fe57713aab885ff7237390f72d9003f157381 (plain) (tree)
1
2
  
                                        























                                                                             








                                                                                

                      




                                                                               
                                                                                            




                                        
                            






                                                
                              



                             
                         
                                  



                                
                             
                                       



                                   



                         





                                                         
                      




                   
                   




















                                                                    
                                 



                                                         
                                                                      

                                                                           
                                   



                                                                            

                                                                               

                   

                                                                           



                                 
                                            










                                                                               

                                                 









                                                                            
                  


                                     


                                                  





                                     

                                                
                                 
                  
          







                                      




                                     






                                     
                                     
                                     



                                                                  
                                                      









                                                                                















                                                 
                                            
          

 


                                                                   









                                                                    




                                                                              





                                                                              
                                                                  
 
                        


                                           
                                        

                                     

                                                               
                                                 
                                                            
                                                   



                                                       
                                            
                                                      
 










                                                                                
 
                                                          
                            







                                                                             

                                        




                                                                              


                   
                            



























                                                           
                            












                                            






                                                                              

                   
                                                       


                                                   

                                     
 

                                          

                                
                           



                                  
                                               




                                                                 
                                                            

           
                                    

   
                              
                                  
                                                 
                                                 



                               
                                    
                                                  
                                                  


           
                                           
                                                     
                                                       
                                                     

           
                                                       
                                                      
                                                        


           




                                                               
                                                                       


                                         
                                                
                           


                               















                                                                   

                                   






                                               
                                          




                                              
                                                    



                   

                                                                     
                              
                                                        
                                                                   

   



                                                                      




                                                                                              




                                                                      
                                     
                                                         








                                           
                                                  





                                        




                                                          
                                           





                                                                  


                    


                                            
                                                        
                                                                       
                                                          



                           











































                                                                                


                                              


























                                                                     
                            




































                                                                   
                                                   






                                             
                                     





                                                       







                                 
                                 

                                            

                                                             











                                                                       



                                                                                                 

                                                                       
                                          



                                                                                               
                                                  
                                                 
                   
                                                                                


                                                                           
                                                                                            
                   
 
                                                                             
                                      
                                                                      





                                                                        




















                                                                          


               
                                    





                                                                           
                                               
                              
                                                                   

















                                                   
                                                                 
                                                                 


                                                              


                                                     
                                                   

                                          

                                                                            


                                                                                                    

                                                 
                                                             
                            







                                                                                                          



                                                                     
                                                                            
                                                             


                                                                     

                                                                            

                                                                                  

                                                                        
                            


                                                                                                            
                                                                     




                                                                                                            




                                                           


                                                                   






                                                          
                                
                                               

                          
                                             
                                                            







                                                                           
                                                                       


                                                                                                            




                                                                                               


                                                                                                            



                                                           
                                                                                  




                                                         
                                         

                                                                         
                                                
                                       
                   


                                                                
                                                                             
                                                              

           

                                                                                   

                                             
                                               




                                                                    
                                                  
                                                   

                                                                    




                                                                         
                                                
                                                           
                                                                                       



                                                                              
                                                                                           










                                                                              
                                              
                                                                         
                                                             






                                                                

                                                                                   














                                                                               
                                                               





                                                   

                                                                
                                                                     
                                                               

                                                                               





                                             





                                                          
                                                          


                                                                         
                                                               








                                                                                       
                                                                          





                                                                
                                                                      


                                               
                                              
                                                   


                                                                        




                                                                       
                                                                                          















                                                                           
                                                  
                                                                           
                                                                     













                                                                  


                                                                          







                                                      
                                                        


                                                                         























                                                                    









                                                                          









                                                                               

                                                                                 

           
                                                    














































































                                                                             
                                          









                                    
                                           

                                                    

                                                        




                                                      
                                         

                                                      

                                            


                                     


                                          
                                              





                                                            


                                                        



                                           
                                 
                           
                                                          
           
                                                  

                                   
                                                                  

                            
                             

                                               

                                                                          


                                                                                                       
                                                  




                                             
                                               

                                  


                                                          

                                                   


                                                  


                                                 




                                                   
                                              
                                                    
                                           


                                                                        
                                                               










                                                                           

                                                          
           
                                              
                                                          
                                                     
                                                         
                                                   

                                                                   
                                                    







                                                                            



                                               



                                   





                            
                                                                 






                                                        
                                                      








                                                 
                                    









                                                                
                                                                       



                                                                     


                                                                             

                                                          

                                       
                                      


                   
                            

                

                               
                                                      

   


                                                                                


                                         



                                                                 

   


                                         



                                                                        






                                              
                       




                                               

   
                   




                                               



















                              

                                                      








                               
                                                         













                                                   
                                    
                                                                         





                                               


                    
                                     




                                               

   
                   


                                                                       
                           




                                                             





                                                                    
                                        
                  
                         
                   




















                                                                                
                                                                        

                                    
                           


                                                     
                                                                            
     
                                                               
      
                                                            

           

                                                                   








                                          
                       





                                                                  
                                          





























                                         

                                           
                                    

                                                   
   

                                                



                                                


                                     
                                                        


                                                                     

                                              


           
         
--
-- SPDX-License-Identifier: BSD-2-Clause
--
-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
--
-- Redistribution and use in source and binary forms, with or without
-- modification, are permitted provided that the following conditions
-- are met:
-- 1. Redistributions of source code must retain the above copyright
--    notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright
--    notice, this list of conditions and the following disclaimer in the
--    documentation and/or other materials provided with the distribution.
--
-- THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-- ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-- SUCH DAMAGE.
--


-- We generally assume that this script will be run by flua, however we've
-- carefully crafted modules for it that mimic interfaces provided by modules
-- available in ports.  Currently, this script is compatible with lua from ports
-- along with the compatible luafilesystem and lua-posix modules.
local lfs = require("lfs")
local unistd = require("posix.unistd")

local savesyscall = -1
local maxsyscall = -1
local generated_tag = "@" .. "generated"

-- Default configuration; any of these may get replaced by a configuration file
-- optionally specified.
local config = {
	os_id_keyword = "FreeBSD",		-- obsolete, ignored on input, not generated
	abi_func_prefix = "",
	sysnames = "syscalls.c",
	sysproto = "../sys/sysproto.h",
	sysproto_h = "_SYS_SYSPROTO_H_",
	syshdr = "../sys/syscall.h",
	sysmk = "/dev/null",
	syssw = "init_sysent.c",
	syscallprefix = "SYS_",
	switchname = "sysent",
	namesname = "syscallnames",
	systrace = "systrace_args.c",
	capabilities_conf = "capabilities.conf",
	capenabled = {},
	compat_set = "native",
	mincompat = 0,
	abi_type_suffix = "",
	abi_flags = "",
	abi_flags_mask = 0,
	abi_headers = "",
	abi_intptr_t = "intptr_t",
	abi_size_t = "size_t",
	abi_u_long = "u_long",
	abi_long = "long",
	abi_semid_t = "semid_t",
	abi_ptr_array_t = "",
	ptr_intptr_t_cast = "intptr_t",
	syscall_abi_change = "",
	sys_abi_change = {},
	syscall_no_abi_change = "",
	sys_no_abi_change = {},
	obsol = "",
	obsol_dict = {},
	unimpl = "",
	unimpl_dict = {},
}

local config_modified = {}
local cleantmp = true
local tmpspace = "/tmp/sysent." .. unistd.getpid() .. "/"

local output_files = {
	"sysnames",
	"syshdr",
	"sysmk",
	"syssw",
	"systrace",
	"sysproto",
}

-- These ones we'll create temporary files for; generation purposes.
local temp_files = {
	"sysaue",
	"sysdcl",
	"syscompat",
	"syscompatdcl",
	"sysent",
	"sysinc",
	"sysarg",
	"sysprotoend",
	"systracetmp",
	"systraceret",
}

-- Opened files
local files = {}

local function cleanup()
	for _, v in pairs(files) do
		assert(v:close())
	end
	if cleantmp then
		if lfs.dir(tmpspace) then
			for fname in lfs.dir(tmpspace) do
				if fname ~= "." and fname ~= ".." then
					assert(os.remove(tmpspace .. "/" ..
					    fname))
				end
			end
		end

		if lfs.attributes(tmpspace) and not lfs.rmdir(tmpspace) then
			assert(io.stderr:write("Failed to clean up tmpdir: " ..
			    tmpspace .. "\n"))
		end
	else
		assert(io.stderr:write("Temp files left in " .. tmpspace ..
		    "\n"))
	end
end

local function abort(status, msg)
	assert(io.stderr:write(msg .. "\n"))
	cleanup()
	os.exit(status)
end

-- Each entry should have a value so we can represent abi flags as a bitmask
-- for convenience.  One may also optionally provide an expr; this gets applied
-- to each argument type to indicate whether this argument is subject to ABI
-- change given the configured flags.
local known_abi_flags = {
	long_size = {
		value	= 0x00000001,
		exprs	= {
			"_Contains[a-z_]*_long_",
			"^long [a-z0-9_]+$",
			"long [*]",
			"size_t [*]",
			-- semid_t is not included because it is only used
			-- as an argument or written out individually and
			-- said writes are handled by the ksem framework.
			-- Technically a sign-extension issue exists for
			-- arguments, but because semid_t is actually a file
			-- descriptor negative 32-bit values are invalid
			-- regardless of sign-extension.
		},
	},
	time_t_size = {
		value	= 0x00000002,
		exprs	= {
			"_Contains[a-z_]*_timet_",
		},
	},
	pointer_args = {
		value	= 0x00000004,
	},
	pointer_size = {
		value	= 0x00000008,
		exprs	= {
			"_Contains[a-z_]*_ptr_",
			"[*][*]",
		},
	},
	pair_64bit = {
		value	= 0x00000010,
		exprs	= {
			"^dev_t[ ]*$",
			"^id_t[ ]*$",
			"^off_t[ ]*$",
		},
	},
}

local known_flags = {
	STD		= 0x00000001,
	OBSOL		= 0x00000002,
	RESERVED	= 0x00000004,
	UNIMPL		= 0x00000008,
	NODEF		= 0x00000010,
	NOARGS		= 0x00000020,
	NOPROTO		= 0x00000040,
	NOSTD		= 0x00000080,
	NOTSTATIC	= 0x00000100,
	CAPENABLED	= 0x00000200,
	SYSMUX		= 0x00000400,

	-- Compat flags start from here.  We have plenty of space.
}

-- All compat option entries should have five entries:
--	definition: The preprocessor macro that will be set for this
--	compatlevel: The level this compatibility should be included at.  This
--	    generally represents the version of FreeBSD that it is compatible
--	    with, but ultimately it's just the level of mincompat in which it's
--	    included.
--	flag: The name of the flag in syscalls.master.
--	prefix: The prefix to use for _args and syscall prototype.  This will be
--	    used as-is, without "_" or any other character appended.
--	descr: The description of this compat option in init_sysent.c comments.
-- The special "stdcompat" entry will cause the other five to be autogenerated.
local compat_option_sets = {
	native = {
		{
			definition = "COMPAT_43",
			compatlevel = 3,
			flag = "COMPAT",
			prefix = "o",
			descr = "old",
		},
		{ stdcompat = "FREEBSD4" },
		{ stdcompat = "FREEBSD6" },
		{ stdcompat = "FREEBSD7" },
		{ stdcompat = "FREEBSD10" },
		{ stdcompat = "FREEBSD11" },
		{ stdcompat = "FREEBSD12" },
		{ stdcompat = "FREEBSD13" },
		{ stdcompat = "FREEBSD14" },
	},
}

-- compat_options will be resolved to a set from the configuration.
local compat_options

local function trim(s, char)
	if s == nil then
		return nil
	end
	if char == nil then
		char = "%s"
	end
	return s:gsub("^" .. char .. "+", ""):gsub(char .. "+$", "")
end

-- config looks like a shell script; in fact, the previous makesyscalls.sh
-- script actually sourced it in.  It had a pretty common format, so we should
-- be fine to make various assumptions
local function process_config(file)
	local cfg = {}
	local comment_line_expr = "^%s*#.*"
	-- We capture any whitespace padding here so we can easily advance to
	-- the end of the line as needed to check for any trailing bogus bits.
	-- Alternatively, we could drop the whitespace and instead try to
	-- use a pattern to strip out the meaty part of the line, but then we
	-- would need to sanitize the line for potentially special characters.
	local line_expr = "^([%w%p]+%s*)=(%s*[`\"]?[^\"`]*[`\"]?)"

	if not file then
		return nil, "No file given"
	end

	local fh = assert(io.open(file))

	for nextline in fh:lines() do
		-- Strip any whole-line comments
		nextline = nextline:gsub(comment_line_expr, "")
		-- Parse it into key, value pairs
		local key, value = nextline:match(line_expr)
		if key ~= nil and value ~= nil then
			local kvp = key .. "=" .. value
			key = trim(key)
			value = trim(value)
			local delim = value:sub(1,1)
			if delim == '"' then
				local trailing_context

				-- Strip off the key/value part
				trailing_context = nextline:sub(kvp:len() + 1)
				-- Strip off any trailing comment
				trailing_context = trailing_context:gsub("#.*$",
				    "")
				-- Strip off leading/trailing whitespace
				trailing_context = trim(trailing_context)
				if trailing_context ~= "" then
					print(trailing_context)
					abort(1, "Malformed line: " .. nextline)
				end

				value = trim(value, delim)
			else
				-- Strip off potential comments
				value = value:gsub("#.*$", "")
				-- Strip off any padding whitespace
				value = trim(value)
				if value:match("%s") then
					abort(1, "Malformed config line: " ..
					    nextline)
				end
			end
			cfg[key] = value
		elseif not nextline:match("^%s*$") then
			-- Make sure format violations don't get overlooked
			-- here, but ignore blank lines.  Comments are already
			-- stripped above.
			abort(1, "Malformed config line: " .. nextline)
		end
	end

	assert(io.close(fh))
	return cfg
end

local function grab_capenabled(file, open_fail_ok)
	local capentries = {}
	local commentExpr = "#.*"

	if file == nil then
		print "No file"
		return {}
	end

	local fh = io.open(file)
	if fh == nil then
		if not open_fail_ok then
			abort(1, "Failed to open " .. file)
		end
		return {}
	end

	for nextline in fh:lines() do
		-- Strip any comments
		nextline = nextline:gsub(commentExpr, "")
		if nextline ~= "" then
			capentries[nextline] = true
		end
	end

	assert(io.close(fh))
	return capentries
end

local function process_compat()
	local nval = 0
	for _, v in pairs(known_flags) do
		if v > nval then
			nval = v
		end
	end

	nval = nval << 1
	for _, v in pairs(compat_options) do
		if v.stdcompat ~= nil then
			local stdcompat = v.stdcompat
			v.definition = "COMPAT_" .. stdcompat:upper()
			v.compatlevel = tonumber(stdcompat:match("([0-9]+)$"))
			v.flag = stdcompat:gsub("FREEBSD", "COMPAT")
			v.prefix = stdcompat:lower() .. "_"
			v.descr = stdcompat:lower()
		end

		local tmpname = "sys" .. v.flag:lower()
		local dcltmpname = tmpname .. "dcl"
		files[tmpname] = io.tmpfile()
		files[dcltmpname] = io.tmpfile()
		v.tmp = tmpname
		v.dcltmp = dcltmpname

		known_flags[v.flag] = nval
		v.mask = nval
		nval = nval << 1

		v.count = 0
	end
end

local function process_abi_flags()
	local flags, mask = config.abi_flags, 0
	for txtflag in flags:gmatch("([^|]+)") do
		if known_abi_flags[txtflag] == nil then
			abort(1, "Unknown abi_flag: " .. txtflag)
		end

		mask = mask | known_abi_flags[txtflag].value
	end

	config.abi_flags_mask = mask
end

local function process_obsol()
	local obsol = config.obsol
	for syscall in obsol:gmatch("([^ ]+)") do
		config.obsol_dict[syscall] = true
	end
end

local function process_unimpl()
	local unimpl = config.unimpl
	for syscall in unimpl:gmatch("([^ ]+)") do
		config.unimpl_dict[syscall] = true
	end
end

local function process_syscall_abi_change()
	local changes_abi = config.syscall_abi_change
	for syscall in changes_abi:gmatch("([^ ]+)") do
		config.sys_abi_change[syscall] = true
	end

	local no_changes = config.syscall_no_abi_change
	for syscall in no_changes:gmatch("([^ ]+)") do
		config.sys_no_abi_change[syscall] = true
	end
end

local function abi_changes(name)
	if known_abi_flags[name] == nil then
		abort(1, "abi_changes: unknown flag: " .. name)
	end

	return config.abi_flags_mask & known_abi_flags[name].value ~= 0
end

local function strip_abi_prefix(funcname)
	local abiprefix = config.abi_func_prefix
	local stripped_name
	if funcname == nil then
		return nil
	end
	if abiprefix ~= "" and funcname:find("^" .. abiprefix) then
		stripped_name = funcname:gsub("^" .. abiprefix, "")
	else
		stripped_name = funcname
	end

	return stripped_name
end

local function read_file(tmpfile)
	if files[tmpfile] == nil then
		print("Not found: " .. tmpfile)
		return
	end

	local fh = files[tmpfile]
	assert(fh:seek("set"))
	return assert(fh:read("a"))
end

local function write_line(tmpfile, line)
	if files[tmpfile] == nil then
		print("Not found: " .. tmpfile)
		return
	end
	assert(files[tmpfile]:write(line))
end

local function write_line_pfile(tmppat, line)
	for k in pairs(files) do
		if k:match(tmppat) ~= nil then
			assert(files[k]:write(line))
		end
	end
end

-- Check both literal intptr_t and the abi version because this needs
-- to work both before and after the substitution
local function isptrtype(type)
	return type:find("*") or type:find("caddr_t") or
	    type:find("intptr_t") or type:find(config.abi_intptr_t)
end

local function isptrarraytype(type)
	return type:find("[*][*]") or type:find("[*][ ]*const[ ]*[*]")
end

-- Find types that are always 64-bits wide
local function is64bittype(type)
	return type:find("^dev_t[ ]*$") or type:find("^id_t[ ]*$") or type:find("^off_t[ ]*$")
end

local process_syscall_def

-- These patterns are processed in order on any line that isn't empty.
local pattern_table = {
	{
		-- To be removed soon
		pattern = "%s*$" .. config.os_id_keyword,
		process = function(_, _)
			-- Ignore... ID tag
		end,
	},
	{
		dump_prevline = true,
		pattern = "^#%s*include",
		process = function(line)
			line = line .. "\n"
			write_line("sysinc", line)
		end,
	},
	{
		dump_prevline = true,
		pattern = "^#",
		process = function(line)
			if line:find("^#%s*if") then
				savesyscall = maxsyscall
			elseif line:find("^#%s*else") then
				maxsyscall = savesyscall
			end
			line = line .. "\n"
			write_line("sysent", line)
			write_line("sysdcl", line)
			write_line("sysarg", line)
			write_line_pfile("syscompat[0-9]*$", line)
			write_line("sysnames", line)
			write_line_pfile("systrace.*", line)
		end,
	},
	{
		dump_prevline = true,
		pattern = "%%ABI_HEADERS%%",
		process = function()
			if config.abi_headers ~= "" then
				local line = config.abi_headers .. "\n"
				write_line("sysinc", line)
			end
		end,
	},
	{
		-- Buffer anything else
		pattern = ".+",
		process = function(line, prevline)
			local incomplete = line:find("\\$") ~= nil
			-- Lines that end in \ get the \ stripped
			-- Lines that start with a syscall number, prepend \n
			line = trim(line):gsub("\\$", "")
			if line:find("^[0-9]") and prevline then
				process_syscall_def(prevline)
				prevline = nil
			end

			prevline = (prevline or '') .. line
			incomplete = incomplete or prevline:find(",$") ~= nil
			incomplete = incomplete or prevline:find("{") ~= nil and
			    prevline:find("}") == nil
			if prevline:find("^[0-9]") and not incomplete then
				process_syscall_def(prevline)
				prevline = nil
			end

			return prevline
		end,
	},
}

local function process_sysfile(file)
	local capentries = {}
	local commentExpr = "^%s*;.*"

	if file == nil then
		print "No file"
		return {}
	end

	local fh = io.open(file)
	if fh == nil then
		print("Failed to open " .. file)
		return {}
	end

	local function do_match(nextline, prevline)
		local pattern, handler, dump
		for _, v in pairs(pattern_table) do
			pattern = v.pattern
			handler = v.process
			dump = v.dump_prevline
			if nextline:match(pattern) then
				if dump and prevline then
					process_syscall_def(prevline)
					prevline = nil
				end

				return handler(nextline, prevline)
			end
		end

		abort(1, "Failed to handle: " .. nextline)
	end

	local prevline
	for nextline in fh:lines() do
		-- Strip any comments
		nextline = nextline:gsub(commentExpr, "")
		if nextline ~= "" then
			prevline = do_match(nextline, prevline)
		end
	end

	-- Dump any remainder
	if prevline ~= nil and prevline:find("^[0-9]") then
		process_syscall_def(prevline)
	end

	assert(io.close(fh))
	return capentries
end

local function get_mask(flags)
	local mask = 0
	for _, v in ipairs(flags) do
		if known_flags[v] == nil then
			abort(1, "Checking for unknown flag " .. v)
		end

		mask = mask | known_flags[v]
	end

	return mask
end

local function get_mask_pat(pflags)
	local mask = 0
	for k, v in pairs(known_flags) do
		if k:find(pflags) then
			mask = mask | v
		end
	end

	return mask
end

local function align_sysent_comment(col)
	write_line("sysent", "\t")
	col = col + 8 - col % 8
	while col < 56 do
		write_line("sysent", "\t")
		col = col + 8
	end
end

local function strip_arg_annotations(arg)
	arg = arg:gsub("_Contains_[^ ]*[_)] ?", "")
	arg = arg:gsub("_In[^ ]*[_)] ?", "")
	arg = arg:gsub("_Out[^ ]*[_)] ?", "")
	return trim(arg)
end

local function check_abi_changes(arg)
	for k, v in pairs(known_abi_flags) do
		local exprs = v.exprs
		if abi_changes(k) and exprs ~= nil then
			for _, e in pairs(exprs) do
				if arg:find(e) then
					return true
				end
			end
		end
	end

	return false
end

local function process_args(args)
	local funcargs = {}
	local changes_abi = false

	for arg in args:gmatch("([^,]+)") do
		local arg_abi_change = check_abi_changes(arg)
		changes_abi = changes_abi or arg_abi_change

		arg = strip_arg_annotations(arg)

		local argname = arg:match("([^* ]+)$")

		-- argtype is... everything else.
		local argtype = trim(arg:gsub(argname .. "$", ""), nil)

		if argtype == "" and argname == "void" then
			goto out
		end

		-- is64bittype() needs a bare type so check it after argname
		-- is removed
		changes_abi = changes_abi or (abi_changes("pair_64bit") and is64bittype(argtype))

		argtype = argtype:gsub("intptr_t", config.abi_intptr_t)
		argtype = argtype:gsub("semid_t", config.abi_semid_t)
		if isptrtype(argtype) then
			argtype = argtype:gsub("size_t", config.abi_size_t)
			argtype = argtype:gsub("^long", config.abi_long);
			argtype = argtype:gsub("^u_long", config.abi_u_long);
			argtype = argtype:gsub("^const u_long", "const " .. config.abi_u_long);
		elseif argtype:find("^long$") then
			argtype = config.abi_long
		end
		if isptrarraytype(argtype) and config.abi_ptr_array_t ~= "" then
			-- `* const *` -> `**`
			argtype = argtype:gsub("[*][ ]*const[ ]*[*]", "**")
			-- e.g., `struct aiocb **` -> `uint32_t *`
			argtype = argtype:gsub("[^*]*[*]", config.abi_ptr_array_t .. " ", 1)
		end

		-- XX TODO: Forward declarations? See: sysstubfwd in CheriBSD
		if arg_abi_change then
			local abi_type_suffix = config.abi_type_suffix
			argtype = argtype:gsub("(struct [^ ]*)", "%1" ..
			    abi_type_suffix)
			argtype = argtype:gsub("(union [^ ]*)", "%1" ..
			    abi_type_suffix)
		end

		if abi_changes("pair_64bit") and is64bittype(argtype) then
			if #funcargs % 2 == 1 then
				funcargs[#funcargs + 1] = {
					type = "int",
					name = "_pad",
				}
			end
			funcargs[#funcargs + 1] = {
				type = "uint32_t",
				name = argname .. "1",
			}
			funcargs[#funcargs + 1] = {
				type = "uint32_t",
				name = argname .. "2",
			}
		else
			funcargs[#funcargs + 1] = {
				type = argtype,
				name = argname,
			}
		end
	end

	::out::
	return funcargs, changes_abi
end

local function handle_noncompat(sysnum, thr_flag, flags, sysflags, rettype,
    auditev, syscallret, funcname, funcalias, funcargs, argalias)
	local argssize

	if flags & known_flags.SYSMUX ~= 0 then
		argssize = "0"
	elseif #funcargs > 0 or flags & known_flags.NODEF ~= 0 then
		argssize = "AS(" .. argalias .. ")"
	else
		argssize = "0"
	end

	write_line("systrace", string.format([[
	/* %s */
	case %d: {
]], funcname, sysnum))
	write_line("systracetmp", string.format([[
	/* %s */
	case %d:
]], funcname, sysnum))
	write_line("systraceret", string.format([[
	/* %s */
	case %d:
]], funcname, sysnum))

	if #funcargs > 0 and flags & known_flags.SYSMUX == 0 then
		write_line("systracetmp", "\t\tswitch (ndx) {\n")
		write_line("systrace", string.format(
		    "\t\tstruct %s *p = params;\n", argalias))


		local argtype, argname, desc, padding
		padding = ""
		for idx, arg in ipairs(funcargs) do
			argtype = arg.type
			argname = arg.name

			argtype = trim(argtype:gsub("__restrict$", ""), nil)
			if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
				write_line("systracetmp", "#ifdef PAD64_REQUIRED\n")
			end
			-- Pointer arg?
			if argtype:find("*") then
				desc = "userland " .. argtype
			else
				desc = argtype;
			end
			write_line("systracetmp", string.format(
			    "\t\tcase %d%s:\n\t\t\tp = \"%s\";\n\t\t\tbreak;\n",
			    idx - 1, padding, desc))
			if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
				padding = " - _P_"
				write_line("systracetmp", "#define _P_ 0\n#else\n#define _P_ 1\n#endif\n")
			end

			if isptrtype(argtype) then
				write_line("systrace", string.format(
				    "\t\tuarg[a++] = (%s)p->%s; /* %s */\n",
				    config.ptr_intptr_t_cast,
				    argname, argtype))
			elseif argtype == "union l_semun" then
				write_line("systrace", string.format(
				    "\t\tuarg[a++] = p->%s.buf; /* %s */\n",
				    argname, argtype))
			elseif argtype:sub(1,1) == "u" or argtype == "size_t" then
				write_line("systrace", string.format(
				    "\t\tuarg[a++] = p->%s; /* %s */\n",
				    argname, argtype))
			else
				if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
					write_line("systrace", "#ifdef PAD64_REQUIRED\n")
				end
				write_line("systrace", string.format(
				    "\t\tiarg[a++] = p->%s; /* %s */\n",
				    argname, argtype))
				if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
					write_line("systrace", "#endif\n")
				end
			end
		end

		write_line("systracetmp",
		    "\t\tdefault:\n\t\t\tbreak;\n\t\t};\n")
		if padding ~= "" then
			write_line("systracetmp", "#undef _P_\n\n")
		end

		write_line("systraceret", string.format([[
		if (ndx == 0 || ndx == 1)
			p = "%s";
		break;
]], syscallret))
	end
	local n_args = #funcargs
	if flags & known_flags.SYSMUX ~= 0 then
		n_args = 0
	end
	write_line("systrace", string.format(
	    "\t\t*n_args = %d;\n\t\tbreak;\n\t}\n", n_args))
	write_line("systracetmp", "\t\tbreak;\n")

	local nargflags = get_mask({"NOARGS", "NOPROTO", "NODEF"})
	if flags & nargflags == 0 then
		if #funcargs > 0 then
			write_line("sysarg", string.format("struct %s {\n",
			    argalias))
			for _, v in ipairs(funcargs) do
				local argname, argtype = v.name, v.type
				if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
					write_line("sysarg", "#ifdef PAD64_REQUIRED\n")
				end
				write_line("sysarg", string.format(
				    "\tchar %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];\n",
				    argname, argtype,
				    argtype, argname,
				    argname, argtype))
				if argtype == "int" and argname == "_pad" and abi_changes("pair_64bit") then
					write_line("sysarg", "#endif\n")
				end
			end
			write_line("sysarg", "};\n")
		else
			write_line("sysarg", string.format(
			    "struct %s {\n\tsyscallarg_t dummy;\n};\n", argalias))
		end
	end

	local protoflags = get_mask({"NOPROTO", "NODEF"})
	if flags & protoflags == 0 then
		local sys_prefix = "sys_"
		if funcname == "nosys" or funcname == "lkmnosys" or
		    funcname == "sysarch" or funcname:find("^freebsd") or
		    funcname:find("^linux") then
			sys_prefix = ""
		end
		write_line("sysdcl", string.format(
		    "%s\t%s%s(struct thread *, struct %s *);\n",
		    rettype, sys_prefix, funcname, argalias))
		write_line("sysaue", string.format("#define\t%sAUE_%s\t%s\n",
		    config.syscallprefix, funcalias, auditev))
	end

	write_line("sysent",
	    string.format("\t{ .sy_narg = %s, .sy_call = (sy_call_t *)", argssize))
	local column = 8 + 2 + #argssize + 15

	if flags & known_flags.SYSMUX ~= 0 then
		write_line("sysent", string.format(
		    "nosys, .sy_auevent = AUE_NULL, " ..
		    ".sy_flags = %s, .sy_thrcnt = SY_THR_STATIC },",
		    sysflags))
		column = column + #"nosys" + #"AUE_NULL" + 3
	elseif flags & known_flags.NOSTD ~= 0 then
		write_line("sysent", string.format(
		    "lkmressys, .sy_auevent = AUE_NULL, " ..
		    ".sy_flags = %s, .sy_thrcnt = SY_THR_ABSENT },",
		    sysflags))
		column = column + #"lkmressys" + #"AUE_NULL" + 3
	else
		if funcname == "nosys" or funcname == "lkmnosys" or
		    funcname == "sysarch" or funcname:find("^freebsd") or
		    funcname:find("^linux") then
			write_line("sysent", string.format(
			    "%s, .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
			    funcname, auditev, sysflags, thr_flag))
			column = column + #funcname + #auditev + #sysflags + 3
		else
			write_line("sysent", string.format(
			    "sys_%s, .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
			    funcname, auditev, sysflags, thr_flag))
			column = column + #funcname + #auditev + #sysflags + 7
		end
	end

	align_sysent_comment(column)
	write_line("sysent", string.format("/* %d = %s */\n",
	    sysnum, funcalias))
	write_line("sysnames", string.format("\t\"%s\",\t\t\t/* %d = %s */\n",
	    funcalias, sysnum, funcalias))

	if flags & known_flags.NODEF == 0 then
		write_line("syshdr", string.format("#define\t%s%s\t%d\n",
		    config.syscallprefix, funcalias, sysnum))
		write_line("sysmk", string.format(" \\\n\t%s.o",
		    funcalias))
	end
end

local function handle_obsol(sysnum, funcname, comment)
	write_line("sysent",
	    "\t{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, " ..
	    ".sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT },")
	align_sysent_comment(34)

	write_line("sysent", string.format("/* %d = obsolete %s */\n",
	    sysnum, comment))
	write_line("sysnames", string.format(
	    "\t\"obs_%s\",\t\t\t/* %d = obsolete %s */\n",
	    funcname, sysnum, comment))
	write_line("syshdr", string.format("\t\t\t\t/* %d is obsolete %s */\n",
	    sysnum, comment))
end

local function handle_compat(sysnum, thr_flag, flags, sysflags, rettype,
    auditev, funcname, funcalias, funcargs, argalias)
	local argssize, out, outdcl, wrap, prefix, descr

	if #funcargs > 0 or flags & known_flags.NODEF ~= 0 then
		argssize = "AS(" .. argalias .. ")"
	else
		argssize = "0"
	end

	for _, v in pairs(compat_options) do
		if flags & v.mask ~= 0 then
			if config.mincompat > v.compatlevel then
				funcname = strip_abi_prefix(funcname)
				funcname = v.prefix .. funcname
				return handle_obsol(sysnum, funcname, funcname)
			end
			v.count = v.count + 1
			out = v.tmp
			outdcl = v.dcltmp
			wrap = v.flag:lower()
			prefix = v.prefix
			descr = v.descr
			goto compatdone
		end
	end

	::compatdone::
	local dprotoflags = get_mask({"NOPROTO", "NODEF"})
	local nargflags = dprotoflags | known_flags.NOARGS
	if #funcargs > 0 and flags & nargflags == 0 then
		write_line(out, string.format("struct %s {\n", argalias))
		for _, v in ipairs(funcargs) do
			local argname, argtype = v.name, v.type
			write_line(out, string.format(
			    "\tchar %s_l_[PADL_(%s)]; %s %s; char %s_r_[PADR_(%s)];\n",
			    argname, argtype,
			    argtype, argname,
			    argname, argtype))
		end
		write_line(out, "};\n")
	elseif flags & nargflags == 0 then
		write_line("sysarg", string.format(
		    "struct %s {\n\tsyscallarg_t dummy;\n};\n", argalias))
	end
	if flags & dprotoflags == 0 then
		write_line(outdcl, string.format(
		    "%s\t%s%s(struct thread *, struct %s *);\n",
		    rettype, prefix, funcname, argalias))
		write_line("sysaue", string.format(
		    "#define\t%sAUE_%s%s\t%s\n", config.syscallprefix,
		    prefix, funcname, auditev))
	end

	if flags & known_flags.NOSTD ~= 0 then
		write_line("sysent", string.format(
		    "\t{ .sy_narg = %s, .sy_call = (sy_call_t *)%s, " ..
		    ".sy_auevent = %s, .sy_flags = 0, " ..
		    ".sy_thrcnt = SY_THR_ABSENT },",
		    "0", "lkmressys", "AUE_NULL"))
		align_sysent_comment(8 + 2 + #"0" + 15 + #"lkmressys" +
		    #"AUE_NULL" + 3)
	else
		write_line("sysent", string.format(
		    "\t{ %s(%s,%s), .sy_auevent = %s, .sy_flags = %s, .sy_thrcnt = %s },",
		    wrap, argssize, funcname, auditev, sysflags, thr_flag))
		align_sysent_comment(8 + 9 + #argssize + 1 + #funcname +
		    #auditev + #sysflags + 4)
	end

	write_line("sysent", string.format("/* %d = %s %s */\n",
	    sysnum, descr, funcalias))
	write_line("sysnames", string.format(
	    "\t\"%s.%s\",\t\t/* %d = %s %s */\n",
	    wrap, funcalias, sysnum, descr, funcalias))
	-- Do not provide freebsdN_* symbols in libc for < FreeBSD 7
	local nosymflags = get_mask({"COMPAT", "COMPAT4", "COMPAT6"})
	if flags & nosymflags ~= 0 then
		write_line("syshdr", string.format(
		    "\t\t\t\t/* %d is %s %s */\n",
		    sysnum, descr, funcalias))
	elseif flags & known_flags.NODEF == 0 then
		write_line("syshdr", string.format("#define\t%s%s%s\t%d\n",
		    config.syscallprefix, prefix, funcalias, sysnum))
		write_line("sysmk", string.format(" \\\n\t%s%s.o",
		    prefix, funcalias))
	end
end

local function handle_unimpl(sysnum, sysstart, sysend, comment)
	if sysstart == nil and sysend == nil then
		sysstart = tonumber(sysnum)
		sysend = tonumber(sysnum)
	end

	sysnum = sysstart
	while sysnum <= sysend do
		write_line("sysent", string.format(
		    "\t{ .sy_narg = 0, .sy_call = (sy_call_t *)nosys, " ..
		    ".sy_auevent = AUE_NULL, .sy_flags = 0, " ..
		    ".sy_thrcnt = SY_THR_ABSENT },\t\t\t/* %d = %s */\n",
		    sysnum, comment))
		write_line("sysnames", string.format(
		    "\t\"#%d\",\t\t\t/* %d = %s */\n",
		    sysnum, sysnum, comment))
		sysnum = sysnum + 1
	end
end

local function handle_reserved(sysnum, sysstart, sysend)
	handle_unimpl(sysnum, sysstart, sysend, "reserved for local use")
end

process_syscall_def = function(line)
	local sysstart, sysend, flags, funcname, sysflags
	local thr_flag, syscallret
	local orig = line
	flags = 0
	thr_flag = "SY_THR_STATIC"

	-- Parse out the interesting information first
	local initialExpr = "^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s*"
	local sysnum, auditev, allflags = line:match(initialExpr)

	if sysnum == nil or auditev == nil or allflags == nil then
		-- XXX TODO: Better?
		abort(1, "Completely malformed: " .. line)
	end

	if sysnum:find("-") then
		sysstart, sysend = sysnum:match("^([%d]+)-([%d]+)$")
		if sysstart == nil or sysend == nil then
			abort(1, "Malformed range: " .. sysnum)
		end
		sysnum = nil
		sysstart = tonumber(sysstart)
		sysend = tonumber(sysend)
		if sysstart ~= maxsyscall + 1 then
			abort(1, "syscall number out of sync, missing " ..
			    maxsyscall + 1)
		end
	else
		sysnum = tonumber(sysnum)
		if sysnum ~= maxsyscall + 1 then
			abort(1, "syscall number out of sync, missing " ..
			    maxsyscall + 1)
		end
	end

	-- Split flags
	for flag in allflags:gmatch("([^|]+)") do
		if known_flags[flag] == nil then
			abort(1, "Unknown flag " .. flag .. " for " ..  sysnum)
		end
		flags = flags | known_flags[flag]
	end

	if (flags & get_mask({"RESERVED", "UNIMPL"})) == 0 and sysnum == nil then
		abort(1, "Range only allowed with RESERVED and UNIMPL: " .. line)
	end

	if (flags & known_flags.NOTSTATIC) ~= 0 then
		thr_flag = "SY_THR_ABSENT"
	end

	-- Strip earlier bits out, leave declaration + alt
	line = line:gsub("^.+" .. allflags .. "%s*", "")

	local decl_fnd = line:find("^{") ~= nil
	if decl_fnd and line:find("}") == nil then
		abort(1, "Malformed, no closing brace: " .. line)
	end

	local decl, alt
	if decl_fnd then
		line = line:gsub("^{", "")
		decl, alt = line:match("([^}]*)}[%s]*(.*)$")
	else
		alt = line
	end

	if decl == nil and alt == nil then
		abort(1, "Malformed bits: " .. line)
	end

	local funcalias, funcomment, argalias, rettype, args
	if not decl_fnd and alt ~= nil and alt ~= "" then
		-- Peel off one entry for name
		funcname = trim(alt:match("^([^%s]+)"), nil)
		alt = alt:gsub("^([^%s]+)[%s]*", "")
	end
	-- Do we even need it?
	if flags & get_mask({"OBSOL", "UNIMPL"}) ~= 0 then
		local NF = 0
		for _ in orig:gmatch("[^%s]+") do
			NF = NF + 1
		end

		funcomment = funcname or ''
		if NF < 6 then
			funcomment = funcomment .. " " .. alt
		end

		funcomment = trim(funcomment)

--		if funcname ~= nil then
--		else
--			funcomment = trim(alt)
--		end
		goto skipalt
	end

	if alt ~= nil and alt ~= "" then
		local altExpr = "^([^%s]+)%s+([^%s]+)%s+([^%s]+)"
		funcalias, argalias, rettype = alt:match(altExpr)
		funcalias = trim(funcalias)
		if funcalias == nil or argalias == nil or rettype == nil then
			abort(1, "Malformed alt: " .. line)
		end
	end
	if decl_fnd then
		-- Don't clobber rettype set in the alt information
		if rettype == nil then
			rettype = "int"
		end
		-- Peel off the return type
		syscallret = line:match("([^%s]+)%s")
		line = line:match("[^%s]+%s(.+)")
		-- Pointer incoming
		if line:sub(1,1) == "*" then
			syscallret = syscallret .. " "
		end
		while line:sub(1,1) == "*" do
			line = line:sub(2)
			syscallret = syscallret .. "*"
		end
		funcname = line:match("^([^(]+)%(")
		if funcname == nil then
			abort(1, "Not a signature? " .. line)
		end
		args = line:match("^[^(]+%((.+)%)[^)]*$")
		args = trim(args, '[,%s]')
	end

	::skipalt::

	if funcname == nil then
		funcname = funcalias
	end

	funcname = trim(funcname)

	if config.obsol_dict[funcname] then
		local compat_prefix = ""
		for _, v in pairs(compat_options) do
			if flags & v.mask ~= 0 then
				compat_prefix = v.prefix
				goto obsol_compat_done
			end
		end
		::obsol_compat_done::
		args = nil
		flags = known_flags.OBSOL
		funcomment = compat_prefix .. funcname
	end
	if config.unimpl_dict[funcname] then
		flags = known_flags.UNIMPL
		funcomment = funcname
	end

	sysflags = "0"

	-- NODEF events do not get audited
	if flags & known_flags.NODEF ~= 0 then
		auditev = 'AUE_NULL'
	end

	-- If applicable; strip the ABI prefix from the name
	local stripped_name = strip_abi_prefix(funcname)

	if flags & known_flags.CAPENABLED ~= 0 or
	    config.capenabled[funcname] ~= nil or
	    config.capenabled[stripped_name] ~= nil then
		sysflags = "SYF_CAPENABLED"
	end

	local funcargs = {}
	local changes_abi = false
	if args ~= nil then
		funcargs, changes_abi = process_args(args)
	end
	if config.sys_no_abi_change[funcname] then
		changes_abi = false
	end
	local noproto = config.abi_flags ~= "" and not changes_abi

	local argprefix = ''
	local funcprefix = ''
	if abi_changes("pointer_args") then
		for _, v in ipairs(funcargs) do
			if isptrtype(v.type) then
				if config.sys_no_abi_change[funcname] then
					print("WARNING: " .. funcname ..
					    " in syscall_no_abi_change, but pointers args are present")
				end
				changes_abi = true
				goto ptrfound
			end
		end
		::ptrfound::
	end
	if config.sys_abi_change[funcname] then
		changes_abi = true
	end
	if changes_abi then
		-- argalias should be:
		--   COMPAT_PREFIX + ABI Prefix + funcname
		argprefix = config.abi_func_prefix
		funcprefix = config.abi_func_prefix
		funcalias = funcprefix .. funcname
		noproto = false
	end
	if funcname ~= nil then
		funcname = funcprefix .. funcname
	end
	if funcalias == nil or funcalias == "" then
		funcalias = funcname
	end

	if argalias == nil and funcname ~= nil then
		argalias = funcname .. "_args"
		for _, v in pairs(compat_options) do
			local mask = v.mask
			if (flags & mask) ~= 0 then
				-- Multiple aliases doesn't seem to make
				-- sense.
				argalias = v.prefix .. argalias
				goto out
			end
		end
		::out::
	elseif argalias ~= nil then
		argalias = argprefix .. argalias
	end

	local ncompatflags = get_mask({"STD", "NODEF", "NOARGS", "NOPROTO",
	    "NOSTD"})
	local compatflags = get_mask_pat("COMPAT.*")
	if noproto or flags & known_flags.SYSMUX ~= 0 then
		flags = flags | known_flags.NOPROTO;
	end
	if flags & known_flags.OBSOL ~= 0 then
		handle_obsol(sysnum, funcname, funcomment)
	elseif flags & known_flags.RESERVED ~= 0 then
		handle_reserved(sysnum, sysstart, sysend)
	elseif flags & known_flags.UNIMPL ~= 0 then
		handle_unimpl(sysnum, sysstart, sysend, funcomment)
	elseif flags & compatflags ~= 0 then
		if flags & known_flags.STD ~= 0 then
			abort(1, "Incompatible COMPAT/STD: " .. line)
		end
		handle_compat(sysnum, thr_flag, flags, sysflags, rettype,
		    auditev, funcname, funcalias, funcargs, argalias)
	elseif flags & ncompatflags ~= 0 then
		handle_noncompat(sysnum, thr_flag, flags, sysflags, rettype,
		    auditev, syscallret, funcname, funcalias, funcargs,
		    argalias)
	else
		abort(1, "Bad flags? " .. line)
	end

	if sysend ~= nil then
		maxsyscall = sysend
	elseif sysnum ~= nil then
		maxsyscall = sysnum
	end
end

-- Entry point

if #arg < 1 or #arg > 2 then
	error("usage: " .. arg[0] .. " input-file <config-file>")
end

local sysfile, configfile = arg[1], arg[2]

-- process_config either returns nil and a message, or a
-- table that we should merge into the global config
if configfile ~= nil then
	local res = assert(process_config(configfile))

	for k, v in pairs(res) do
		if v ~= config[k] then
			config[k] = v
			config_modified[k] = true
		end
	end
end

local compat_set = config.compat_set
if compat_set ~= "" then
	if not compat_option_sets[compat_set] then
		abort(1, "Undefined compat set: " .. compat_set)
	end

	compat_options = compat_option_sets[compat_set]
else
	compat_options = {}
end

-- We ignore errors here if we're relying on the default configuration.
if not config_modified.capenabled then
	config.capenabled = grab_capenabled(config.capabilities_conf,
	    config_modified.capabilities_conf == nil)
elseif config.capenabled ~= "" then
	-- Due to limitations in the config format mostly, we'll have a comma
	-- separated list.  Parse it into lines
	local capenabled = {}
	-- print("here: " .. config.capenabled)
	for sysc in config.capenabled:gmatch("([^,]+)") do
		capenabled[sysc] = true
	end
	config.capenabled = capenabled
end
process_compat()
process_abi_flags()
process_syscall_abi_change()
process_obsol()
process_unimpl()

if not lfs.mkdir(tmpspace) then
	error("Failed to create tempdir " .. tmpspace)
end

-- XXX Revisit the error handling here, we should probably move the rest of this
-- into a function that we pcall() so we can catch the errors and clean up
-- gracefully.
for _, v in ipairs(temp_files) do
	local tmpname = tmpspace .. v
	files[v] = io.open(tmpname, "w+")
	-- XXX Revisit these with a pcall() + error handler
	if not files[v] then
		abort(1, "Failed to open temp file: " .. tmpname)
	end
end

for _, v in ipairs(output_files) do
	local tmpname = tmpspace .. v
	files[v] = io.open(tmpname, "w+")
	-- XXX Revisit these with a pcall() + error handler
	if not files[v] then
		abort(1, "Failed to open temp output file: " .. tmpname)
	end
end

-- Write out all of the preamble bits
write_line("sysent", string.format([[

/* The casts are bogus but will do for now. */
struct sysent %s[] = {
]], config.switchname))

write_line("syssw", string.format([[/*
 * System call switch table.
 *
 * DO NOT EDIT-- this file is automatically %s.
 */

]], generated_tag))

write_line("sysarg", string.format([[/*
 * System call prototypes.
 *
 * DO NOT EDIT-- this file is automatically %s.
 */

#ifndef %s
#define	%s

#include <sys/signal.h>
#include <sys/acl.h>
#include <sys/cpuset.h>
#include <sys/domainset.h>
#include <sys/_ffcounter.h>
#include <sys/_semaphore.h>
#include <sys/ucontext.h>
#include <sys/wait.h>

#include <bsm/audit_kevents.h>

struct proc;

struct thread;

#define	PAD_(t)	(sizeof(syscallarg_t) <= sizeof(t) ? \
		0 : sizeof(syscallarg_t) - sizeof(t))

#if BYTE_ORDER == LITTLE_ENDIAN
#define	PADL_(t)	0
#define	PADR_(t)	PAD_(t)
#else
#define	PADL_(t)	PAD_(t)
#define	PADR_(t)	0
#endif

]], generated_tag, config.sysproto_h, config.sysproto_h))
if abi_changes("pair_64bit") then
	write_line("sysarg", string.format([[
#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
#define PAD64_REQUIRED
#endif
]]))
end
if abi_changes("pair_64bit") then
	write_line("systrace", string.format([[
#if !defined(PAD64_REQUIRED) && !defined(__amd64__)
#define PAD64_REQUIRED
#endif
]]))
end
for _, v in pairs(compat_options) do
	write_line(v.tmp, string.format("\n#ifdef %s\n\n", v.definition))
end

write_line("sysnames", string.format([[/*
 * System call names.
 *
 * DO NOT EDIT-- this file is automatically %s.
 */

const char *%s[] = {
]], generated_tag, config.namesname))

write_line("syshdr", string.format([[/*
 * System call numbers.
 *
 * DO NOT EDIT-- this file is automatically %s.
 */

]], generated_tag))

write_line("sysmk", string.format([[# FreeBSD system call object files.
# DO NOT EDIT-- this file is automatically %s.
MIASM = ]], generated_tag))

write_line("systrace", string.format([[/*
 * System call argument to DTrace register array converstion.
 *
 * DO NOT EDIT-- this file is automatically %s.
 * This file is part of the DTrace syscall provider.
 */

static void
systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
{
	int64_t *iarg = (int64_t *)uarg;
	int a = 0;
	switch (sysnum) {
]], generated_tag))

write_line("systracetmp", [[static void
systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
{
	const char *p = NULL;
	switch (sysnum) {
]])

write_line("systraceret", [[static void
systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
{
	const char *p = NULL;
	switch (sysnum) {
]])

-- Processing the sysfile will parse out the preprocessor bits and put them into
-- the appropriate place.  Any syscall-looking lines get thrown into the sysfile
-- buffer, one per line, for later processing once they're all glued together.
process_sysfile(sysfile)

write_line("sysinc",
    "\n#define AS(name) (sizeof(struct name) / sizeof(syscallarg_t))\n")

for _, v in pairs(compat_options) do
	if v.count > 0 then
		write_line("sysinc", string.format([[

#ifdef %s
#define %s(n, name) .sy_narg = n, .sy_call = (sy_call_t *)__CONCAT(%s, name)
#else
#define %s(n, name) .sy_narg = 0, .sy_call = (sy_call_t *)nosys
#endif
]], v.definition, v.flag:lower(), v.prefix, v.flag:lower()))
	end

	write_line(v.dcltmp, string.format("\n#endif /* %s */\n\n",
	    v.definition))
end

write_line("sysprotoend", string.format([[

#undef PAD_
#undef PADL_
#undef PADR_

#endif /* !%s */
]], config.sysproto_h))

write_line("sysmk", "\n")
write_line("sysent", "};\n")
write_line("sysnames", "};\n")
-- maxsyscall is the highest seen; MAXSYSCALL should be one higher
write_line("syshdr", string.format("#define\t%sMAXSYSCALL\t%d\n",
    config.syscallprefix, maxsyscall + 1))
write_line("systrace", [[
	default:
		*n_args = 0;
		break;
	};
}
]])

write_line("systracetmp", [[
	default:
		break;
	};
	if (p != NULL)
		strlcpy(desc, p, descsz);
}
]])

write_line("systraceret", [[
	default:
		break;
	};
	if (p != NULL)
		strlcpy(desc, p, descsz);
}
]])

-- Finish up; output
write_line("syssw", read_file("sysinc"))
write_line("syssw", read_file("sysent"))

write_line("sysproto", read_file("sysarg"))
write_line("sysproto", read_file("sysdcl"))
for _, v in pairs(compat_options) do
	write_line("sysproto", read_file(v.tmp))
	write_line("sysproto", read_file(v.dcltmp))
end
write_line("sysproto", read_file("sysaue"))
write_line("sysproto", read_file("sysprotoend"))

write_line("systrace", read_file("systracetmp"))
write_line("systrace", read_file("systraceret"))

for _, v in ipairs(output_files) do
	local target = config[v]
	if target ~= "/dev/null" then
		local fh = assert(io.open(target, "w+"))
		if fh == nil then
			abort(1, "Failed to open '" .. target .. "'")
		end
		assert(fh:write(read_file(v)))
		assert(fh:close())
	end
end

cleanup()