1#!/usr/libexec/flua 2-- 3-- SPDX-License-Identifier: BSD-2-Clause 4-- 5-- Copyright (c) 2024 Tyler Baxter <agge@FreeBSD.org> 6-- Copyright (c) 2023 Warner Losh <imp@bsdimp.com> 7-- Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> 8-- 9 10-- Setup to be a module, or ran as its own script. 11local systrace_args = {} 12local script = not pcall(debug.getlocal, 4, 1) -- TRUE if script. 13if script then 14 -- Add library root to the package path. 15 local path = arg[0]:gsub("/[^/]+.lua$", "") 16 package.path = package.path .. ";" .. path .. "/../?.lua" 17end 18 19local FreeBSDSyscall = require("core.freebsd-syscall") 20local util = require("tools.util") 21local generator = require("tools.generator") 22 23-- File has not been decided yet; config will decide file. Default defined as 24-- /dev/null. 25systrace_args.file = "/dev/null" 26 27function systrace_args.generate(tbl, config, fh) 28 -- Grab the master system calls table. 29 local s = tbl.syscalls 30 31 -- Bind the generator to the parameter file. 32 local gen = generator:new({}, fh) 33 gen.storage_levels = {} -- make sure storage is clear 34 35 -- 64-bit padding preprocessor directive. 36 gen:pad64(config.abiChanges("pair_64bit")) 37 38 -- Write the generated preamble. 39 gen:preamble( 40 "System call argument to DTrace register array conversion.\n" .. 41 "\n" .. 42 "This file is part of the DTrace syscall provider.") 43 44 gen:write(string.format([[ 45static void 46systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) 47{ 48 int64_t *iarg = (int64_t *)uarg; 49 int a = 0; 50 switch (sysnum) { 51]])) 52 53 gen:store(string.format([[ 54static void 55systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) 56{ 57 const char *p = NULL; 58 switch (sysnum) { 59]]), 1) 60 61 gen:store(string.format([[ 62static void 63systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) 64{ 65 const char *p = NULL; 66 switch (sysnum) { 67]]), 2) 68 69 for _, v in pairs(s) do 70 71 -- Handle non compat: 72 if v:native() then 73 gen:write(string.format([[ 74 /* %s */ 75 case %d: { 76]], v.name, v.num)) 77 78 gen:store(string.format([[ 79 /* %s */ 80 case %d: 81]], v.name, v.num), 1) 82 83 gen:store(string.format([[ 84 /* %s */ 85 case %d: 86]], v.name, v.num), 2) 87 88 local n_args = #v.args 89 if v.type.SYSMUX then 90 n_args = 0 91 end 92 93 if #v.args > 0 and not v.type.SYSMUX then 94 local padding = "" 95 96 gen:write(string.format([[ 97 struct %s *p = params; 98]], 99 v.arg_alias)) 100 101 gen:store([[ 102 switch (ndx) { 103]], 104 1) 105 106 for idx, arg in ipairs(v.args) do 107 local argtype = util.trim( 108 arg.type:gsub( 109 "__restrict$", ""), nil) 110 if argtype == "int" and 111 arg.name == "_pad" and 112 config.abiChanges("pair_64bit") then 113 gen:store( 114 "#ifdef PAD64_REQUIRED\n", 115 1) 116 end 117 118 -- Pointer arg? 119 local desc 120 if argtype:find("*") then 121 desc = "userland " .. argtype 122 else 123 desc = argtype; 124 end 125 126 gen:store(string.format([[ 127 case %d%s: 128 p = "%s"; 129 break; 130]], 131 idx - 1, padding, desc), 1) 132 133 if argtype == "int" and 134 arg.name == "_pad" and 135 config.abiChanges("pair_64bit") then 136 padding = " - _P_" 137 gen:store([[ 138#define _P_ 0 139#else 140#define _P_ 1 141#endif 142]], 143 1) 144 end 145 146 if util.isPtrType(argtype, 147 config.abi_intptr_t) then 148 gen:write(string.format([[ 149 uarg[a++] = (%s)p->%s; /* %s */ 150]], 151 config.ptr_intptr_t_cast, 152 arg.name, argtype)) 153 elseif argtype == "union l_semun" then 154 gen:write(string.format([[ 155 uarg[a++] = p->%s.buf; /* %s */ 156]], 157 arg.name, argtype)) 158 elseif argtype:sub(1,1) == "u" or 159 argtype == "size_t" then 160 gen:write(string.format([[ 161 uarg[a++] = p->%s; /* %s */ 162]], 163 arg.name, argtype)) 164 else 165 if argtype == "int" and 166 arg.name == "_pad" and 167 config.abiChanges( 168 "pair_64bit") then 169 gen:write([[ 170#ifdef PAD64_REQUIRED 171]]) 172 end 173 174 gen:write(string.format([[ 175 iarg[a++] = p->%s; /* %s */ 176]], 177 arg.name, argtype)) 178 179 if argtype == "int" and 180 arg.name == "_pad" and 181 config.abiChanges( 182 "pair_64bit") then 183 gen:write("#endif\n") 184 end 185 end 186 end 187 188 gen:store([[ 189 default: 190 break; 191 }; 192]], 193 1) 194 195 if padding ~= "" then 196 gen:store("#undef _P_\n\n", 1) 197 end 198 199 gen:store(string.format([[ 200 if (ndx == 0 || ndx == 1) 201 p = "%s"; 202 break; 203]], v.ret), 2) 204 end 205 206 gen:write(string.format("\t\t*n_args = %d;\n\t\tbreak;\n\t}\n", 207 n_args)) 208 gen:store("\t\tbreak;\n", 1) 209 210 -- Handle compat (everything >= FREEBSD3): 211 -- Do nothing, only for native. 212 end 213 end 214 215 gen:write([[ 216 default: 217 *n_args = 0; 218 break; 219 }; 220} 221]]) 222 gen:store([[ 223 default: 224 break; 225 }; 226 if (p != NULL) 227 strlcpy(desc, p, descsz); 228} 229]], 1) 230 gen:store([[ 231 default: 232 break; 233 }; 234 if (p != NULL) 235 strlcpy(desc, p, descsz); 236} 237]], 2) 238 239 -- Write all stored lines. 240 if gen.storage_levels ~= nil then 241 gen:writeStorage() 242 end 243 244end 245 246-- Entry of script: 247if script then 248 local config = require("config") 249 250 if #arg < 1 or #arg > 2 then 251 error("usage: " .. arg[0] .. " syscall.master") 252 end 253 254 local sysfile, configfile = arg[1], arg[2] 255 256 config.merge(configfile) 257 config.mergeCompat() 258 259 -- The parsed system call table. 260 local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} 261 262 systrace_args.file = config.systrace -- change file here 263 systrace_args.generate(tbl, config, systrace_args.file) 264end 265 266-- Return the module. 267return systrace_args 268