1-- 2-- SPDX-License-Identifier: BSD-2-Clause 3-- 4-- Copyright (c) 2021-2024 SRI International 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 10local config = require("config") 11local util = require("tools.util") 12 13local scarg = {} 14 15scarg.__index = scarg 16 17-- Check this argument against config for ABI changes from native. Return TRUE 18-- if there are. 19local function checkAbiChanges(arg) 20 for k, v in pairs(config.known_abi_flags) do 21 if config.abiChanges(k) and v ~= nil then 22 for _, e in pairs(v) do 23 if arg:find(e) then 24 return true 25 end 26 end 27 end 28 end 29 return false 30end 31 32-- Extracts the Microsoft(R) SAL annotations from this argument. 33local function extractArgAnnotations(arg) 34 local annotations = {} 35 for ann in arg:gmatch("_Contains_[^ ]*[_)]") do 36 table.insert(annotations, ann) 37 end 38 for ann in arg:gmatch("_In[^ ]*[_)]") do 39 table.insert(annotations, ann) 40 end 41 for ann in arg:gmatch("_Out[^ ]*[_)]") do 42 table.insert(annotations, ann) 43 end 44 return table.concat(annotations, " ") 45end 46 47-- Strips the Microsoft(R) SAL annotations from this argument. 48local function stripArgAnnotations(arg) 49 arg = arg:gsub("_Contains_[^ ]*[_)] ?", "") 50 arg = arg:gsub("_In[^ ]*[_)] ?", "") 51 arg = arg:gsub("_Out[^ ]*[_)] ?", "") 52 return util.trim(arg) 53end 54 55-- Preprocessing of this argument. 56function scarg:init(line) 57 -- Trim whitespace and trailing comma. We don't want them here; 58 -- these can mess with our processing of this argument. 59 line = util.trim(line) -- This provides a clearer abort error. 60 self.scarg = util.trim(line, ',') 61 62 self.arg_abi_change = checkAbiChanges(self.scarg) 63 self.changes_abi = self.arg_abi_change 64 self.annotation = extractArgAnnotations(self.scarg) 65 self.scarg = stripArgAnnotations(self.scarg) 66 67 self.name = self.scarg:match("([^* ]+)$") 68 -- Our pattern might produce a Lua pattern sequence; that's a malformed 69 -- declaration. 70 local status, type = pcall(function() 71 return util.trim(self.scarg:gsub(self.name .. "$", ""), nil) 72 end) 73 if not status then 74 util.abort(1, "Malformed argument line: " .. line) 75 end 76 self.type = type 77end 78 79-- Processes this argument. 80-- Flags if there's ABI changes from native, converts this argument to the 81-- target ABI, and handles 64-bit argument pairing. 82-- Returns TRUE if this argument is processed and ready to add. 83-- Returns FALSE if it shouldn't be added (the argument type is void). 84function scarg:process() 85 if self.type ~= "" and self.name ~= "void" then 86 -- util.is64bitType() needs a bare type so check it after 87 -- argname is removed. 88 self.changes_abi = self.changes_abi or 89 (config.abiChanges("pair_64bit") and 90 util.is64bitType(self.type)) 91 92 self.type = self.type:gsub("intptr_t", config.abi_intptr_t) 93 self.type = self.type:gsub("semid_t", config.abi_semid_t) 94 95 if util.isPtrType(self.type) then 96 self.type = self.type:gsub("size_t", config.abi_size_t) 97 self.type = self.type:gsub("^long", config.abi_long) 98 self.type = self.type:gsub("^u_long", config.abi_u_long) 99 self.type = self.type:gsub("^const u_long", "const " .. 100 config.abi_u_long) 101 elseif self.type:find("^long$") then 102 self.type = config.abi_long 103 end 104 105 if util.isPtrArrayType(self.type) and 106 config.abi_ptr_array_t ~= "" then 107 -- `* const *` -> `**` 108 self.type = self.type:gsub("[*][ ]*const[ ]*[*]", "**") 109 -- e.g., `struct aiocb **` -> `uint32_t *` 110 self.type = self.type:gsub("[^*]*[*]", 111 config.abi_ptr_array_t .. " ", 1) 112 end 113 114 if self.arg_abi_change then 115 self.type = self.type:gsub("(struct [^ ]*)", "%1" .. 116 config.abi_type_suffix) 117 self.type = self.type:gsub("(union [^ ]*)", "%1" .. 118 config.abi_type_suffix) 119 end 120 return true 121 end 122 return false 123end 124 125-- For pairing 64-bit arguments, pad if necessary. 126-- Returns TRUE if this argument was padded. 127local function pad(tbl) 128 if #tbl % 2 == 1 then 129 table.insert(tbl, { 130 type = "int", 131 name = "_pad", 132 }) 133 return true 134 end 135 return false 136end 137 138-- To append to a system call's argument table. Appends to the end. 139function scarg:append(tbl) 140 if config.abiChanges("pair_64bit") and util.is64bitType(self.type) then 141 pad(tbl) -- Needs argument padding. 142 table.insert(tbl, { 143 type = "uint32_t", 144 name = self.name .. "1", 145 annotation = self.annotation or "", 146 }) 147 table.insert(tbl, { 148 type = "uint32_t", 149 name = self.name .. "2", 150 annotation = "", 151 }) 152 else 153 table.insert(tbl, { 154 type = self.type, 155 name = self.name, 156 annotation = self.annotation or "", 157 }) 158 end 159end 160 161-- Returns TRUE if this argument has ABI changes from native. 162-- EXAMPLE: 32-bit argument for freebsd32. 163function scarg:changesAbi() 164 return self.changes_abi 165end 166 167function scarg:new(obj, line) 168 obj = obj or { } 169 setmetatable(obj, self) 170 self.__index = self 171 172 -- ABI changes that we only want in this scope. 173 self.arg_abi_change = false 174 -- ABI changes that we want the system call object to see. 175 self.changes_abi = false 176 177 obj:init(line) 178 179 return obj 180end 181 182return scarg 183