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 gen:write(v.prolog); 72 gen:store(v.prolog, 1); 73 gen:store(v.prolog, 2); 74 75 -- Handle non compat: 76 if v:native() then 77 gen:write(string.format([[ 78 /* %s */ 79 case %d: { 80]], v.name, v.num)) 81 82 gen:store(string.format([[ 83 /* %s */ 84 case %d: 85]], v.name, v.num), 1) 86 87 gen:store(string.format([[ 88 /* %s */ 89 case %d: 90]], v.name, v.num), 2) 91 92 local n_args = #v.args 93 if v.type.SYSMUX then 94 n_args = 0 95 end 96 97 if #v.args > 0 and not v.type.SYSMUX then 98 local padding = "" 99 100 gen:write(string.format([[ 101 struct %s *p = params; 102]], 103 v.arg_alias)) 104 105 gen:store([[ 106 switch (ndx) { 107]], 108 1) 109 110 for idx, arg in ipairs(v.args) do 111 local argtype = util.trim( 112 arg.type:gsub( 113 "__restrict$", ""), nil) 114 if argtype == "int" and 115 arg.name == "_pad" and 116 config.abiChanges("pair_64bit") then 117 gen:store( 118 "#ifdef PAD64_REQUIRED\n", 119 1) 120 end 121 122 -- Pointer arg? 123 local desc 124 if argtype:find("*") then 125 desc = "userland " .. argtype 126 else 127 desc = argtype; 128 end 129 130 gen:store(string.format([[ 131 case %d%s: 132 p = "%s"; 133 break; 134]], 135 idx - 1, padding, desc), 1) 136 137 if argtype == "int" and 138 arg.name == "_pad" and 139 config.abiChanges("pair_64bit") then 140 padding = " - _P_" 141 gen:store([[ 142#define _P_ 0 143#else 144#define _P_ 1 145#endif 146]], 147 1) 148 end 149 150 if util.isPtrType(argtype, 151 config.abi_intptr_t) then 152 gen:write(string.format([[ 153 uarg[a++] = (%s)p->%s; /* %s */ 154]], 155 config.ptr_intptr_t_cast, 156 arg.name, argtype)) 157 elseif argtype == "union l_semun" then 158 gen:write(string.format([[ 159 uarg[a++] = p->%s.buf; /* %s */ 160]], 161 arg.name, argtype)) 162 elseif argtype:sub(1,1) == "u" or 163 argtype == "size_t" then 164 gen:write(string.format([[ 165 uarg[a++] = p->%s; /* %s */ 166]], 167 arg.name, argtype)) 168 else 169 if argtype == "int" and 170 arg.name == "_pad" and 171 config.abiChanges( 172 "pair_64bit") then 173 gen:write([[ 174#ifdef PAD64_REQUIRED 175]]) 176 end 177 178 gen:write(string.format([[ 179 iarg[a++] = p->%s; /* %s */ 180]], 181 arg.name, argtype)) 182 183 if argtype == "int" and 184 arg.name == "_pad" and 185 config.abiChanges( 186 "pair_64bit") then 187 gen:write("#endif\n") 188 end 189 end 190 end 191 192 gen:store([[ 193 default: 194 break; 195 }; 196]], 197 1) 198 199 if padding ~= "" then 200 gen:store("#undef _P_\n\n", 1) 201 end 202 203 gen:store(string.format([[ 204 if (ndx == 0 || ndx == 1) 205 p = "%s"; 206 break; 207]], v.ret), 2) 208 end 209 210 gen:write(string.format("\t\t*n_args = %d;\n\t\tbreak;\n\t}\n", 211 n_args)) 212 gen:store("\t\tbreak;\n", 1) 213 214 -- Handle compat (everything >= FREEBSD3): 215 -- Do nothing, only for native. 216 end 217 end 218 219 gen:write(tbl.epilog) 220 gen:write([[ 221 default: 222 *n_args = 0; 223 break; 224 }; 225} 226]]) 227 228 gen:store(tbl.epilog, 1) 229 gen:store([[ 230 default: 231 break; 232 }; 233 if (p != NULL) 234 strlcpy(desc, p, descsz); 235} 236]], 1) 237 238 gen:store(tbl.epilog, 2) 239 gen:store([[ 240 default: 241 break; 242 }; 243 if (p != NULL) 244 strlcpy(desc, p, descsz); 245} 246]], 2) 247 248 -- Write all stored lines. 249 if gen.storage_levels ~= nil then 250 gen:writeStorage() 251 end 252 253end 254 255-- Entry of script: 256if script then 257 local config = require("config") 258 259 if #arg < 1 or #arg > 2 then 260 error("usage: " .. arg[0] .. " syscall.master") 261 end 262 263 local sysfile, configfile = arg[1], arg[2] 264 265 config.merge(configfile) 266 config.mergeCompat() 267 268 -- The parsed system call table. 269 local tbl = FreeBSDSyscall:new{sysfile = sysfile, config = config} 270 271 systrace_args.file = config.systrace -- change file here 272 systrace_args.generate(tbl, config, systrace_args.file) 273end 274 275-- Return the module. 276return systrace_args 277