xref: /aosp_15_r20/external/bcc/src/lua/bpf/bpf.lua (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker--[[
2*387f9dfdSAndroid Build Coastguard WorkerCopyright 2016 Marek Vavrusa <[email protected]>
3*387f9dfdSAndroid Build Coastguard Worker
4*387f9dfdSAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License");
5*387f9dfdSAndroid Build Coastguard Workeryou may not use this file except in compliance with the License.
6*387f9dfdSAndroid Build Coastguard WorkerYou may obtain a copy of the License at
7*387f9dfdSAndroid Build Coastguard Worker
8*387f9dfdSAndroid Build Coastguard Workerhttp://www.apache.org/licenses/LICENSE-2.0
9*387f9dfdSAndroid Build Coastguard Worker
10*387f9dfdSAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software
11*387f9dfdSAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS,
12*387f9dfdSAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*387f9dfdSAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and
14*387f9dfdSAndroid Build Coastguard Workerlimitations under the License.
15*387f9dfdSAndroid Build Coastguard Worker]]
16*387f9dfdSAndroid Build Coastguard Worker-- LuaJIT to BPF bytecode compiler.
17*387f9dfdSAndroid Build Coastguard Worker--
18*387f9dfdSAndroid Build Coastguard Worker-- The code generation phase is currently one-pass and produces:
19*387f9dfdSAndroid Build Coastguard Worker-- * Compiled code in BPF bytecode format (https://www.kernel.org/doc/Documentation/networking/filter.txt)
20*387f9dfdSAndroid Build Coastguard Worker-- * Variables with liveness analysis and other meta (spill information, compile-time value)
21*387f9dfdSAndroid Build Coastguard Worker--
22*387f9dfdSAndroid Build Coastguard Worker-- The code generator optimises as much as possible in single pass:
23*387f9dfdSAndroid Build Coastguard Worker-- * Fold compile-time expressions and constant propagation
24*387f9dfdSAndroid Build Coastguard Worker-- * Basic control flow analysis with dead code elimination (based on compile-time expressions)
25*387f9dfdSAndroid Build Coastguard Worker-- * Single-pass optimistic register allocation
26*387f9dfdSAndroid Build Coastguard Worker--
27*387f9dfdSAndroid Build Coastguard Worker-- The first pass doesn't have variable lifetime visibility yet, so it relies on rewriter for further
28*387f9dfdSAndroid Build Coastguard Worker-- optimisations such as:
29*387f9dfdSAndroid Build Coastguard Worker-- * Dead store elimination (first-pass doesn't know if/when the variable is going to be used)
30*387f9dfdSAndroid Build Coastguard Worker-- * Common sub-expression elimination (relies on DCE and liveness analysis)
31*387f9dfdSAndroid Build Coastguard Worker-- * Orphan JMP elimination (removing this in first pass would break previous JMP targets)
32*387f9dfdSAndroid Build Coastguard Worker-- * Better register allocation (needs to be recomputed after optimisations)
33*387f9dfdSAndroid Build Coastguard Worker
34*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require('ffi')
35*387f9dfdSAndroid Build Coastguard Workerlocal bit = require('bit')
36*387f9dfdSAndroid Build Coastguard Workerlocal S = require('syscall')
37*387f9dfdSAndroid Build Coastguard Workerlocal bytecode = require('bpf.ljbytecode')
38*387f9dfdSAndroid Build Coastguard Workerlocal cdef = require('bpf.cdef')
39*387f9dfdSAndroid Build Coastguard Workerlocal proto = require('bpf.proto')
40*387f9dfdSAndroid Build Coastguard Workerlocal builtins = require('bpf.builtins')
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Worker-- Constants
43*387f9dfdSAndroid Build Coastguard Workerlocal ALWAYS, NEVER = -1, -2
44*387f9dfdSAndroid Build Coastguard Workerlocal BPF = ffi.typeof('struct bpf')
45*387f9dfdSAndroid Build Coastguard Workerlocal HELPER = ffi.typeof('struct bpf_func_id')
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker-- Symbolic table of constant expressions over numbers
48*387f9dfdSAndroid Build Coastguard Workerlocal const_expr = {
49*387f9dfdSAndroid Build Coastguard Worker	ADD = function (a, b) return a + b end,
50*387f9dfdSAndroid Build Coastguard Worker	SUB = function (a, b) return a - b end,
51*387f9dfdSAndroid Build Coastguard Worker	DIV = function (a, b) return a / b end,
52*387f9dfdSAndroid Build Coastguard Worker	MOD = function (a, b) return a % b end,
53*387f9dfdSAndroid Build Coastguard Worker	JEQ = function (a, b) return a == b end,
54*387f9dfdSAndroid Build Coastguard Worker	JNE = function (a, b) return a ~= b end,
55*387f9dfdSAndroid Build Coastguard Worker	JGE = function (a, b) return a >= b end,
56*387f9dfdSAndroid Build Coastguard Worker	JGT = function (a, b) return a > b end,
57*387f9dfdSAndroid Build Coastguard Worker}
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard Workerlocal const_width = {
60*387f9dfdSAndroid Build Coastguard Worker	[1] = BPF.B, [2] = BPF.H, [4] = BPF.W, [8] = BPF.DW,
61*387f9dfdSAndroid Build Coastguard Worker}
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker-- Built-ins that are strict only (never compile-time expandable)
64*387f9dfdSAndroid Build Coastguard Workerlocal builtins_strict = {
65*387f9dfdSAndroid Build Coastguard Worker	[ffi.new] = true,
66*387f9dfdSAndroid Build Coastguard Worker	[print]   = true,
67*387f9dfdSAndroid Build Coastguard Worker}
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker-- Deep copy a table
70*387f9dfdSAndroid Build Coastguard Workerlocal function table_copy(t)
71*387f9dfdSAndroid Build Coastguard Worker	local copy = {}
72*387f9dfdSAndroid Build Coastguard Worker	for n,v in pairs(t) do
73*387f9dfdSAndroid Build Coastguard Worker		if type(v) == 'table' then
74*387f9dfdSAndroid Build Coastguard Worker			v = table_copy(v)
75*387f9dfdSAndroid Build Coastguard Worker		end
76*387f9dfdSAndroid Build Coastguard Worker		copy[n] = v
77*387f9dfdSAndroid Build Coastguard Worker	end
78*387f9dfdSAndroid Build Coastguard Worker	return copy
79*387f9dfdSAndroid Build Coastguard Workerend
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard Worker-- Return true if the constant part is a proxy
82*387f9dfdSAndroid Build Coastguard Workerlocal function is_proxy(x)
83*387f9dfdSAndroid Build Coastguard Worker	return type(x) == 'table' and (x.__dissector or x.__map or x.__base)
84*387f9dfdSAndroid Build Coastguard Workerend
85*387f9dfdSAndroid Build Coastguard Worker
86*387f9dfdSAndroid Build Coastguard Worker-- Create compiler closure
87*387f9dfdSAndroid Build Coastguard Workerlocal function create_emitter(env, stackslots, params, param_types)
88*387f9dfdSAndroid Build Coastguard Worker
89*387f9dfdSAndroid Build Coastguard Workerlocal V = {}   -- Variable tracking / register allocator
90*387f9dfdSAndroid Build Coastguard Workerlocal code = { -- Generated code
91*387f9dfdSAndroid Build Coastguard Worker	pc = 0, bc_pc = 0,
92*387f9dfdSAndroid Build Coastguard Worker	insn = ffi.new('struct bpf_insn[4096]'),
93*387f9dfdSAndroid Build Coastguard Worker	fixup = {},
94*387f9dfdSAndroid Build Coastguard Worker	reachable = true,
95*387f9dfdSAndroid Build Coastguard Worker	seen_cmp = nil,
96*387f9dfdSAndroid Build Coastguard Worker}
97*387f9dfdSAndroid Build Coastguard Workerlocal Vstate = {} -- Track variable layout at basic block exits
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker-- Anything below this stack offset is free to use by caller
100*387f9dfdSAndroid Build Coastguard Worker-- @note: There is no tracking memory allocator, so the caller may
101*387f9dfdSAndroid Build Coastguard Worker-- lower it for persistent objects, but such memory will never
102*387f9dfdSAndroid Build Coastguard Worker-- be reclaimed and the caller is responsible for resetting stack
103*387f9dfdSAndroid Build Coastguard Worker-- top whenever the memory below is free to be reused
104*387f9dfdSAndroid Build Coastguard Workerlocal stack_top = (stackslots + 1) * ffi.sizeof('uint64_t')
105*387f9dfdSAndroid Build Coastguard Worker
106*387f9dfdSAndroid Build Coastguard Workerlocal function emit(op, dst, src, off, imm)
107*387f9dfdSAndroid Build Coastguard Worker	local ins = code.insn[code.pc]
108*387f9dfdSAndroid Build Coastguard Worker	ins.code = op
109*387f9dfdSAndroid Build Coastguard Worker	ins.dst_reg = dst
110*387f9dfdSAndroid Build Coastguard Worker	ins.src_reg = src
111*387f9dfdSAndroid Build Coastguard Worker	ins.off = off
112*387f9dfdSAndroid Build Coastguard Worker	ins.imm = imm
113*387f9dfdSAndroid Build Coastguard Worker	code.pc = code.pc + 1
114*387f9dfdSAndroid Build Coastguard Workerend
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Workerlocal function reg_spill(var)
117*387f9dfdSAndroid Build Coastguard Worker	local vinfo = V[var]
118*387f9dfdSAndroid Build Coastguard Worker	assert(vinfo.reg, 'attempt to spill VAR that doesn\'t have an allocated register')
119*387f9dfdSAndroid Build Coastguard Worker	vinfo.spill = (var + 1) * ffi.sizeof('uint64_t') -- Index by (variable number) * (register width)
120*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.MEM + BPF.STX + BPF.DW, 10, vinfo.reg, -vinfo.spill, 0)
121*387f9dfdSAndroid Build Coastguard Worker	vinfo.reg = nil
122*387f9dfdSAndroid Build Coastguard Workerend
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Workerlocal function reg_fill(var, reg)
125*387f9dfdSAndroid Build Coastguard Worker	local vinfo = V[var]
126*387f9dfdSAndroid Build Coastguard Worker	assert(reg, 'attempt to fill variable to register but not register is allocated')
127*387f9dfdSAndroid Build Coastguard Worker	assert(vinfo.spill, 'attempt to fill register with a VAR that isn\'t spilled')
128*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.MEM + BPF.LDX + BPF.DW, reg, 10, -vinfo.spill, 0)
129*387f9dfdSAndroid Build Coastguard Worker	vinfo.reg = reg
130*387f9dfdSAndroid Build Coastguard Worker	vinfo.spill = nil
131*387f9dfdSAndroid Build Coastguard Workerend
132*387f9dfdSAndroid Build Coastguard Worker
133*387f9dfdSAndroid Build Coastguard Worker-- Allocate a register (lazy simple allocator)
134*387f9dfdSAndroid Build Coastguard Workerlocal function reg_alloc(var, reg)
135*387f9dfdSAndroid Build Coastguard Worker	-- Specific register requested, must spill/move existing variable
136*387f9dfdSAndroid Build Coastguard Worker	if reg then
137*387f9dfdSAndroid Build Coastguard Worker		for k,v in pairs(V) do -- Spill any variable that has this register
138*387f9dfdSAndroid Build Coastguard Worker			if v.reg == reg and not v.shadow then
139*387f9dfdSAndroid Build Coastguard Worker				reg_spill(k)
140*387f9dfdSAndroid Build Coastguard Worker				break
141*387f9dfdSAndroid Build Coastguard Worker			end
142*387f9dfdSAndroid Build Coastguard Worker		end
143*387f9dfdSAndroid Build Coastguard Worker		return reg
144*387f9dfdSAndroid Build Coastguard Worker	end
145*387f9dfdSAndroid Build Coastguard Worker	-- Find free or least recently used slot
146*387f9dfdSAndroid Build Coastguard Worker	local last, last_seen, used = nil, 0xffff, 0
147*387f9dfdSAndroid Build Coastguard Worker	for k,v in pairs(V) do
148*387f9dfdSAndroid Build Coastguard Worker		if v.reg then
149*387f9dfdSAndroid Build Coastguard Worker			if not v.live_to or v.live_to < last_seen then
150*387f9dfdSAndroid Build Coastguard Worker				last, last_seen = k, v.live_to or last_seen
151*387f9dfdSAndroid Build Coastguard Worker			end
152*387f9dfdSAndroid Build Coastguard Worker			used = bit.bor(used, bit.lshift(1, v.reg))
153*387f9dfdSAndroid Build Coastguard Worker		end
154*387f9dfdSAndroid Build Coastguard Worker	end
155*387f9dfdSAndroid Build Coastguard Worker	-- Attempt to select a free register from R7-R9 (callee saved)
156*387f9dfdSAndroid Build Coastguard Worker	local free = bit.bnot(used)
157*387f9dfdSAndroid Build Coastguard Worker	if     bit.band(free, 0x80) ~= 0 then reg = 7
158*387f9dfdSAndroid Build Coastguard Worker	elseif bit.band(free,0x100) ~= 0 then reg = 8
159*387f9dfdSAndroid Build Coastguard Worker	elseif bit.band(free,0x200) ~= 0 then reg = 9
160*387f9dfdSAndroid Build Coastguard Worker	end
161*387f9dfdSAndroid Build Coastguard Worker	-- Select another variable to be spilled
162*387f9dfdSAndroid Build Coastguard Worker	if not reg then
163*387f9dfdSAndroid Build Coastguard Worker		assert(last)
164*387f9dfdSAndroid Build Coastguard Worker		reg = V[last].reg
165*387f9dfdSAndroid Build Coastguard Worker		reg_spill(last)
166*387f9dfdSAndroid Build Coastguard Worker	end
167*387f9dfdSAndroid Build Coastguard Worker	assert(reg, 'VAR '..var..'fill/spill failed')
168*387f9dfdSAndroid Build Coastguard Worker	return reg
169*387f9dfdSAndroid Build Coastguard Workerend
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Worker-- Set new variable
172*387f9dfdSAndroid Build Coastguard Workerlocal function vset(var, reg, const, vtype)
173*387f9dfdSAndroid Build Coastguard Worker	-- Must materialise all variables shadowing this variable slot, as it will be overwritten
174*387f9dfdSAndroid Build Coastguard Worker	if V[var] and V[var].reg then
175*387f9dfdSAndroid Build Coastguard Worker		for _, vinfo in pairs(V) do
176*387f9dfdSAndroid Build Coastguard Worker			-- Shadowing variable MUST share the same type and attributes,
177*387f9dfdSAndroid Build Coastguard Worker			-- but the register assignment may have changed
178*387f9dfdSAndroid Build Coastguard Worker			if vinfo.shadow == var then
179*387f9dfdSAndroid Build Coastguard Worker				vinfo.reg = V[var].reg
180*387f9dfdSAndroid Build Coastguard Worker				vinfo.shadow = nil
181*387f9dfdSAndroid Build Coastguard Worker			end
182*387f9dfdSAndroid Build Coastguard Worker		end
183*387f9dfdSAndroid Build Coastguard Worker	end
184*387f9dfdSAndroid Build Coastguard Worker	-- Get precise type for CDATA or attempt to narrow numeric constant
185*387f9dfdSAndroid Build Coastguard Worker	if not vtype and type(const) == 'cdata' then
186*387f9dfdSAndroid Build Coastguard Worker		vtype = ffi.typeof(const)
187*387f9dfdSAndroid Build Coastguard Worker	end
188*387f9dfdSAndroid Build Coastguard Worker	V[var] = {reg=reg, const=const, type=vtype}
189*387f9dfdSAndroid Build Coastguard Worker	-- Track variable source
190*387f9dfdSAndroid Build Coastguard Worker	if V[var].const and type(const) == 'table' then
191*387f9dfdSAndroid Build Coastguard Worker		V[var].source = V[var].const.source
192*387f9dfdSAndroid Build Coastguard Worker	end
193*387f9dfdSAndroid Build Coastguard Workerend
194*387f9dfdSAndroid Build Coastguard Worker
195*387f9dfdSAndroid Build Coastguard Worker-- Materialize (or register) a variable in a register
196*387f9dfdSAndroid Build Coastguard Worker-- If the register is nil, then the a new register is assigned (if not already assigned)
197*387f9dfdSAndroid Build Coastguard Workerlocal function vreg(var, reg, reserve, vtype)
198*387f9dfdSAndroid Build Coastguard Worker	local vinfo = V[var]
199*387f9dfdSAndroid Build Coastguard Worker	assert(vinfo, 'VAR '..var..' not registered')
200*387f9dfdSAndroid Build Coastguard Worker	vinfo.live_to = code.pc-1
201*387f9dfdSAndroid Build Coastguard Worker	if (vinfo.reg and not reg) and not vinfo.shadow then return vinfo.reg end
202*387f9dfdSAndroid Build Coastguard Worker	reg = reg_alloc(var, reg)
203*387f9dfdSAndroid Build Coastguard Worker	-- Materialize variable shadow copy
204*387f9dfdSAndroid Build Coastguard Worker	local src = vinfo
205*387f9dfdSAndroid Build Coastguard Worker	while src.shadow do src = V[src.shadow] end
206*387f9dfdSAndroid Build Coastguard Worker	if reserve then -- luacheck: ignore
207*387f9dfdSAndroid Build Coastguard Worker		-- No load to register occurs
208*387f9dfdSAndroid Build Coastguard Worker	elseif src.reg then
209*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.MOV + BPF.X, reg, src.reg, 0, 0)
210*387f9dfdSAndroid Build Coastguard Worker	elseif src.spill then
211*387f9dfdSAndroid Build Coastguard Worker		vinfo.spill = src.spill
212*387f9dfdSAndroid Build Coastguard Worker		reg_fill(var, reg)
213*387f9dfdSAndroid Build Coastguard Worker	elseif src.const then
214*387f9dfdSAndroid Build Coastguard Worker		vtype = vtype or src.type
215*387f9dfdSAndroid Build Coastguard Worker		if type(src.const) == 'table' and src.const.__base then
216*387f9dfdSAndroid Build Coastguard Worker			-- Load pointer type
217*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.MOV + BPF.X, reg, 10, 0, 0)
218*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.ADD + BPF.K, reg, 0, 0, -src.const.__base)
219*387f9dfdSAndroid Build Coastguard Worker		elseif type(src.const) == 'table' and src.const.__dissector then
220*387f9dfdSAndroid Build Coastguard Worker			-- Load dissector offset (imm32), but keep the constant part (dissector proxy)
221*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.MOV + BPF.K, reg, 0, 0, src.const.off or 0)
222*387f9dfdSAndroid Build Coastguard Worker		elseif vtype and ffi.sizeof(vtype) == 8 then
223*387f9dfdSAndroid Build Coastguard Worker			-- IMM64 must be done in two instructions with imm64 = (lo(imm32), hi(imm32))
224*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.LD + BPF.DW, reg, 0, 0, ffi.cast('uint32_t', src.const))
225*387f9dfdSAndroid Build Coastguard Worker			emit(0, 0, 0, 0, ffi.cast('uint32_t', bit.rshift(bit.rshift(src.const, 16), 16)))
226*387f9dfdSAndroid Build Coastguard Worker			vinfo.const = nil -- The variable is live
227*387f9dfdSAndroid Build Coastguard Worker		else
228*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.MOV + BPF.K, reg, 0, 0, src.const)
229*387f9dfdSAndroid Build Coastguard Worker			vinfo.const = nil -- The variable is live
230*387f9dfdSAndroid Build Coastguard Worker		end
231*387f9dfdSAndroid Build Coastguard Worker	else assert(false, 'VAR '..var..' has neither register nor constant value') end
232*387f9dfdSAndroid Build Coastguard Worker	vinfo.reg = reg
233*387f9dfdSAndroid Build Coastguard Worker	vinfo.shadow = nil
234*387f9dfdSAndroid Build Coastguard Worker	vinfo.live_from = code.pc-1
235*387f9dfdSAndroid Build Coastguard Worker	vinfo.type = vtype or vinfo.type
236*387f9dfdSAndroid Build Coastguard Worker	return reg
237*387f9dfdSAndroid Build Coastguard Workerend
238*387f9dfdSAndroid Build Coastguard Worker
239*387f9dfdSAndroid Build Coastguard Worker-- Copy variable
240*387f9dfdSAndroid Build Coastguard Workerlocal function vcopy(dst, src)
241*387f9dfdSAndroid Build Coastguard Worker	if dst == src then return end
242*387f9dfdSAndroid Build Coastguard Worker	V[dst] = {reg=V[src].reg, const=V[src].const, shadow=src, source=V[src].source, type=V[src].type}
243*387f9dfdSAndroid Build Coastguard Workerend
244*387f9dfdSAndroid Build Coastguard Worker
245*387f9dfdSAndroid Build Coastguard Worker-- Dereference variable of pointer type
246*387f9dfdSAndroid Build Coastguard Workerlocal function vderef(dst_reg, src_reg, vinfo)
247*387f9dfdSAndroid Build Coastguard Worker	-- Dereference map pointers for primitive types
248*387f9dfdSAndroid Build Coastguard Worker	-- BPF doesn't allow pointer arithmetics, so use the entry value
249*387f9dfdSAndroid Build Coastguard Worker	assert(type(vinfo.const) == 'table' and vinfo.const.__dissector, 'cannot dereference a non-pointer variable')
250*387f9dfdSAndroid Build Coastguard Worker	local vtype = vinfo.const.__dissector
251*387f9dfdSAndroid Build Coastguard Worker	local w = ffi.sizeof(vtype)
252*387f9dfdSAndroid Build Coastguard Worker	assert(const_width[w], 'NYI: sizeof('..tostring(vtype)..') not 1/2/4/8 bytes')
253*387f9dfdSAndroid Build Coastguard Worker	if dst_reg ~= src_reg then
254*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.MOV + BPF.X, dst_reg, src_reg, 0, 0)    -- dst = src
255*387f9dfdSAndroid Build Coastguard Worker	end
256*387f9dfdSAndroid Build Coastguard Worker	-- Optimize the NULL check away if provably not NULL
257*387f9dfdSAndroid Build Coastguard Worker	if not vinfo.source or vinfo.source:find('_or_null', 1, true) then
258*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.JMP + BPF.JEQ + BPF.K, src_reg, 0, 1, 0)            -- if (src != NULL)
259*387f9dfdSAndroid Build Coastguard Worker	end
260*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.MEM + BPF.LDX + const_width[w], dst_reg, src_reg, 0, 0) --     dst = *src;
261*387f9dfdSAndroid Build Coastguard Workerend
262*387f9dfdSAndroid Build Coastguard Worker
263*387f9dfdSAndroid Build Coastguard Worker-- Allocate a space for variable
264*387f9dfdSAndroid Build Coastguard Workerlocal function valloc(size, blank)
265*387f9dfdSAndroid Build Coastguard Worker	local base = stack_top
266*387f9dfdSAndroid Build Coastguard Worker	assert(stack_top + size < 512 * 1024, 'exceeded maximum stack size of 512kB')
267*387f9dfdSAndroid Build Coastguard Worker	stack_top = stack_top + size
268*387f9dfdSAndroid Build Coastguard Worker	-- Align to 8 byte boundary
269*387f9dfdSAndroid Build Coastguard Worker	stack_top = math.ceil(stack_top/8)*8
270*387f9dfdSAndroid Build Coastguard Worker	-- Current kernel version doesn't support ARG_PTR_TO_RAW_STACK
271*387f9dfdSAndroid Build Coastguard Worker	-- so we always need to have memory initialized, remove this when supported
272*387f9dfdSAndroid Build Coastguard Worker	if blank then
273*387f9dfdSAndroid Build Coastguard Worker		if type(blank) == 'string' then
274*387f9dfdSAndroid Build Coastguard Worker			local sp = 0
275*387f9dfdSAndroid Build Coastguard Worker			while sp < size do
276*387f9dfdSAndroid Build Coastguard Worker				-- TODO: no BPF_ST + BPF_DW instruction yet
277*387f9dfdSAndroid Build Coastguard Worker				local as_u32 = ffi.new('uint32_t [1]')
278*387f9dfdSAndroid Build Coastguard Worker				local sub = blank:sub(sp+1, sp+ffi.sizeof(as_u32))
279*387f9dfdSAndroid Build Coastguard Worker				ffi.copy(as_u32, sub, #sub)
280*387f9dfdSAndroid Build Coastguard Worker				emit(BPF.MEM + BPF.ST + BPF.W, 10, 0, -(stack_top-sp), as_u32[0])
281*387f9dfdSAndroid Build Coastguard Worker				sp = sp + ffi.sizeof(as_u32)
282*387f9dfdSAndroid Build Coastguard Worker			end
283*387f9dfdSAndroid Build Coastguard Worker		elseif type(blank) == 'boolean' then
284*387f9dfdSAndroid Build Coastguard Worker			reg_alloc(stackslots, 0)
285*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.MOV + BPF.K, 0, 0, 0, 0)
286*387f9dfdSAndroid Build Coastguard Worker			for sp = base+8,stack_top,8 do
287*387f9dfdSAndroid Build Coastguard Worker				emit(BPF.MEM + BPF.STX + BPF.DW, 10, 0, -sp, 0)
288*387f9dfdSAndroid Build Coastguard Worker			end
289*387f9dfdSAndroid Build Coastguard Worker		else error('NYI: will with unknown type '..type(blank)) end
290*387f9dfdSAndroid Build Coastguard Worker	end
291*387f9dfdSAndroid Build Coastguard Worker	return stack_top
292*387f9dfdSAndroid Build Coastguard Workerend
293*387f9dfdSAndroid Build Coastguard Worker
294*387f9dfdSAndroid Build Coastguard Worker-- Turn variable into scalar in register (or constant)
295*387f9dfdSAndroid Build Coastguard Workerlocal function vscalar(a, w)
296*387f9dfdSAndroid Build Coastguard Worker	assert(const_width[w], 'sizeof(scalar variable) must be 1/2/4/8')
297*387f9dfdSAndroid Build Coastguard Worker	local src_reg
298*387f9dfdSAndroid Build Coastguard Worker	-- If source is a pointer, we must dereference it first
299*387f9dfdSAndroid Build Coastguard Worker	if cdef.isptr(V[a].type) then
300*387f9dfdSAndroid Build Coastguard Worker		src_reg = vreg(a)
301*387f9dfdSAndroid Build Coastguard Worker		local tmp_reg = reg_alloc(stackslots, 1) -- Clone variable in tmp register
302*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.MOV + BPF.X, tmp_reg, src_reg, 0, 0)
303*387f9dfdSAndroid Build Coastguard Worker		vderef(tmp_reg, tmp_reg, V[a])
304*387f9dfdSAndroid Build Coastguard Worker		src_reg = tmp_reg -- Materialize and dereference it
305*387f9dfdSAndroid Build Coastguard Worker	-- Source is a value on stack, we must load it first
306*387f9dfdSAndroid Build Coastguard Worker	elseif type(V[a].const) == 'table' and V[a].const.__base > 0 then
307*387f9dfdSAndroid Build Coastguard Worker		src_reg = vreg(a)
308*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.MEM + BPF.LDX + const_width[w], src_reg, 10, -V[a].const.__base, 0)
309*387f9dfdSAndroid Build Coastguard Worker		V[a].type = V[a].const.__dissector
310*387f9dfdSAndroid Build Coastguard Worker		V[a].const = nil -- Value is dereferenced
311*387f9dfdSAndroid Build Coastguard Worker	-- If source is an imm32 number, avoid register load
312*387f9dfdSAndroid Build Coastguard Worker	elseif type(V[a].const) == 'number' and w < 8 then
313*387f9dfdSAndroid Build Coastguard Worker		return nil, V[a].const
314*387f9dfdSAndroid Build Coastguard Worker	-- Load variable from any other source
315*387f9dfdSAndroid Build Coastguard Worker	else
316*387f9dfdSAndroid Build Coastguard Worker		src_reg = vreg(a)
317*387f9dfdSAndroid Build Coastguard Worker	end
318*387f9dfdSAndroid Build Coastguard Worker
319*387f9dfdSAndroid Build Coastguard Worker	return src_reg, nil
320*387f9dfdSAndroid Build Coastguard Workerend
321*387f9dfdSAndroid Build Coastguard Worker
322*387f9dfdSAndroid Build Coastguard Worker-- Emit compensation code at the end of basic block to unify variable set layout on all block exits
323*387f9dfdSAndroid Build Coastguard Worker-- 1. we need to free registers by spilling
324*387f9dfdSAndroid Build Coastguard Worker-- 2. fill registers to match other exits from this BB
325*387f9dfdSAndroid Build Coastguard Workerlocal function bb_end(Vcomp)
326*387f9dfdSAndroid Build Coastguard Worker	for i,v in pairs(V) do
327*387f9dfdSAndroid Build Coastguard Worker		if Vcomp[i] and Vcomp[i].spill and not v.spill then
328*387f9dfdSAndroid Build Coastguard Worker			-- Materialize constant or shadowing variable to be able to spill
329*387f9dfdSAndroid Build Coastguard Worker			if not v.reg and (v.shadow or cdef.isimmconst(v)) then
330*387f9dfdSAndroid Build Coastguard Worker				vreg(i)
331*387f9dfdSAndroid Build Coastguard Worker			end
332*387f9dfdSAndroid Build Coastguard Worker			reg_spill(i)
333*387f9dfdSAndroid Build Coastguard Worker		end
334*387f9dfdSAndroid Build Coastguard Worker	end
335*387f9dfdSAndroid Build Coastguard Worker	for i,v in pairs(V) do
336*387f9dfdSAndroid Build Coastguard Worker		if Vcomp[i] and Vcomp[i].reg and not v.reg then
337*387f9dfdSAndroid Build Coastguard Worker			vreg(i, Vcomp[i].reg)
338*387f9dfdSAndroid Build Coastguard Worker		end
339*387f9dfdSAndroid Build Coastguard Worker		-- Compensate variable metadata change
340*387f9dfdSAndroid Build Coastguard Worker		if Vcomp[i] and Vcomp[i].source then
341*387f9dfdSAndroid Build Coastguard Worker			V[i].source = Vcomp[i].source
342*387f9dfdSAndroid Build Coastguard Worker		end
343*387f9dfdSAndroid Build Coastguard Worker	end
344*387f9dfdSAndroid Build Coastguard Workerend
345*387f9dfdSAndroid Build Coastguard Worker
346*387f9dfdSAndroid Build Coastguard Workerlocal function CMP_STR(a, b, op)
347*387f9dfdSAndroid Build Coastguard Worker	assert(op == 'JEQ' or op == 'JNE', 'NYI: only equivallence stack/string only supports == or ~=')
348*387f9dfdSAndroid Build Coastguard Worker	-- I have no better idea how to implement it than unrolled XOR loop, as we can fixup only one JMP
349*387f9dfdSAndroid Build Coastguard Worker	-- So: X(a,b) = a[0] ^ b[0] | a[1] ^ b[1] | ...
350*387f9dfdSAndroid Build Coastguard Worker	--     EQ(a,b) <=> X == 0
351*387f9dfdSAndroid Build Coastguard Worker	-- This could be optimised by placing early exits by rewriter in second phase for long strings
352*387f9dfdSAndroid Build Coastguard Worker	local base, size = V[a].const.__base, math.min(#b, ffi.sizeof(V[a].type))
353*387f9dfdSAndroid Build Coastguard Worker	local acc, tmp = reg_alloc(stackslots, 0), reg_alloc(stackslots+1, 1)
354*387f9dfdSAndroid Build Coastguard Worker	local sp = 0
355*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.ALU64 + BPF.MOV + BPF.K, acc, 0, 0, 0)
356*387f9dfdSAndroid Build Coastguard Worker	while sp < size do
357*387f9dfdSAndroid Build Coastguard Worker		-- Load string chunk as imm32
358*387f9dfdSAndroid Build Coastguard Worker		local as_u32 = ffi.new('uint32_t [1]')
359*387f9dfdSAndroid Build Coastguard Worker		local sub = b:sub(sp+1, sp+ffi.sizeof(as_u32))
360*387f9dfdSAndroid Build Coastguard Worker		ffi.copy(as_u32, sub, #sub)
361*387f9dfdSAndroid Build Coastguard Worker		-- TODO: make this faster by interleaved load/compare steps with DW length
362*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.MEM + BPF.LDX + BPF.W, tmp, 10, -(base-sp), 0)
363*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.XOR + BPF.K, tmp, 0, 0, as_u32[0])
364*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.OR + BPF.X, acc, tmp, 0, 0)
365*387f9dfdSAndroid Build Coastguard Worker		sp = sp + ffi.sizeof(as_u32)
366*387f9dfdSAndroid Build Coastguard Worker	end
367*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.JMP + BPF[op] + BPF.K, acc, 0, 0xffff, 0)
368*387f9dfdSAndroid Build Coastguard Worker	code.seen_cmp = code.pc-1
369*387f9dfdSAndroid Build Coastguard Workerend
370*387f9dfdSAndroid Build Coastguard Worker
371*387f9dfdSAndroid Build Coastguard Workerlocal function CMP_REG(a, b, op)
372*387f9dfdSAndroid Build Coastguard Worker	-- Fold compile-time expressions
373*387f9dfdSAndroid Build Coastguard Worker	if V[a].const and V[b].const and not (is_proxy(V[a].const) or is_proxy(V[b].const)) then
374*387f9dfdSAndroid Build Coastguard Worker		code.seen_cmp = const_expr[op](V[a].const, V[b].const) and ALWAYS or NEVER
375*387f9dfdSAndroid Build Coastguard Worker	else
376*387f9dfdSAndroid Build Coastguard Worker		-- Comparison against compile-time string or stack memory
377*387f9dfdSAndroid Build Coastguard Worker		if V[b].const and type(V[b].const) == 'string' then
378*387f9dfdSAndroid Build Coastguard Worker			return CMP_STR(a, V[b].const, op)
379*387f9dfdSAndroid Build Coastguard Worker		end
380*387f9dfdSAndroid Build Coastguard Worker		-- The 0xFFFF target here has no significance, it's just a placeholder for
381*387f9dfdSAndroid Build Coastguard Worker		-- compiler to replace it's absolute offset to LJ bytecode insn with a relative
382*387f9dfdSAndroid Build Coastguard Worker		-- offset in BPF program code, verifier will accept only programs with valid JMP targets
383*387f9dfdSAndroid Build Coastguard Worker		local a_reg, b_reg = vreg(a), vreg(b)
384*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.JMP + BPF[op] + BPF.X, a_reg, b_reg, 0xffff, 0)
385*387f9dfdSAndroid Build Coastguard Worker		code.seen_cmp = code.pc-1
386*387f9dfdSAndroid Build Coastguard Worker	end
387*387f9dfdSAndroid Build Coastguard Workerend
388*387f9dfdSAndroid Build Coastguard Worker
389*387f9dfdSAndroid Build Coastguard Workerlocal function CMP_IMM(a, b, op)
390*387f9dfdSAndroid Build Coastguard Worker	local c = V[a].const
391*387f9dfdSAndroid Build Coastguard Worker	if c and not is_proxy(c) then -- Fold compile-time expressions
392*387f9dfdSAndroid Build Coastguard Worker		code.seen_cmp = const_expr[op](c, b) and ALWAYS or NEVER
393*387f9dfdSAndroid Build Coastguard Worker	else
394*387f9dfdSAndroid Build Coastguard Worker		-- Convert imm32 to number
395*387f9dfdSAndroid Build Coastguard Worker		if type(b) == 'string' then
396*387f9dfdSAndroid Build Coastguard Worker			if     #b == 1 then b = b:byte()
397*387f9dfdSAndroid Build Coastguard Worker			elseif cdef.isptr(V[a].type) then
398*387f9dfdSAndroid Build Coastguard Worker				-- String comparison between stack/constant string
399*387f9dfdSAndroid Build Coastguard Worker				return CMP_STR(a, b, op)
400*387f9dfdSAndroid Build Coastguard Worker			elseif #b <= 4 then
401*387f9dfdSAndroid Build Coastguard Worker				-- Convert to u32 with network byte order
402*387f9dfdSAndroid Build Coastguard Worker				local imm = ffi.new('uint32_t[1]')
403*387f9dfdSAndroid Build Coastguard Worker				ffi.copy(imm, b, #b)
404*387f9dfdSAndroid Build Coastguard Worker				b = builtins.hton(imm[0])
405*387f9dfdSAndroid Build Coastguard Worker			else error('NYI: compare register with string, where #string > sizeof(u32)') end
406*387f9dfdSAndroid Build Coastguard Worker		end
407*387f9dfdSAndroid Build Coastguard Worker		-- The 0xFFFF target here has no significance, it's just a placeholder for
408*387f9dfdSAndroid Build Coastguard Worker		-- compiler to replace it's absolute offset to LJ bytecode insn with a relative
409*387f9dfdSAndroid Build Coastguard Worker		-- offset in BPF program code, verifier will accept only programs with valid JMP targets
410*387f9dfdSAndroid Build Coastguard Worker		local reg = vreg(a)
411*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.JMP + BPF[op] + BPF.K, reg, 0, 0xffff, b)
412*387f9dfdSAndroid Build Coastguard Worker		code.seen_cmp = code.pc-1
413*387f9dfdSAndroid Build Coastguard Worker		-- Remember NULL pointer checks as BPF prohibits pointer comparisons
414*387f9dfdSAndroid Build Coastguard Worker		-- and repeated checks wouldn't pass the verifier, only comparisons
415*387f9dfdSAndroid Build Coastguard Worker		-- against constants are checked.
416*387f9dfdSAndroid Build Coastguard Worker		if op == 'JEQ' and tonumber(b) == 0 and V[a].source then
417*387f9dfdSAndroid Build Coastguard Worker			local pos = V[a].source:find('_or_null', 1, true)
418*387f9dfdSAndroid Build Coastguard Worker			if pos then
419*387f9dfdSAndroid Build Coastguard Worker				code.seen_null_guard = a
420*387f9dfdSAndroid Build Coastguard Worker			end
421*387f9dfdSAndroid Build Coastguard Worker		-- Inverse NULL pointer check (if a ~= nil)
422*387f9dfdSAndroid Build Coastguard Worker		elseif op == 'JNE' and tonumber(b) == 0 and V[a].source then
423*387f9dfdSAndroid Build Coastguard Worker			local pos = V[a].source:find('_or_null', 1, true)
424*387f9dfdSAndroid Build Coastguard Worker			if pos then
425*387f9dfdSAndroid Build Coastguard Worker				code.seen_null_guard = a
426*387f9dfdSAndroid Build Coastguard Worker				code.seen_null_guard_inverse = true
427*387f9dfdSAndroid Build Coastguard Worker			end
428*387f9dfdSAndroid Build Coastguard Worker		end
429*387f9dfdSAndroid Build Coastguard Worker	end
430*387f9dfdSAndroid Build Coastguard Workerend
431*387f9dfdSAndroid Build Coastguard Worker
432*387f9dfdSAndroid Build Coastguard Workerlocal function ALU_IMM(dst, a, b, op)
433*387f9dfdSAndroid Build Coastguard Worker	-- Fold compile-time expressions
434*387f9dfdSAndroid Build Coastguard Worker	if V[a].const and not is_proxy(V[a].const) then
435*387f9dfdSAndroid Build Coastguard Worker			assert(cdef.isimmconst(V[a]), 'VAR '..a..' must be numeric')
436*387f9dfdSAndroid Build Coastguard Worker			vset(dst, nil, const_expr[op](V[a].const, b))
437*387f9dfdSAndroid Build Coastguard Worker	-- Now we need to materialize dissected value at DST, and add it
438*387f9dfdSAndroid Build Coastguard Worker	else
439*387f9dfdSAndroid Build Coastguard Worker		vcopy(dst, a)
440*387f9dfdSAndroid Build Coastguard Worker		local dst_reg = vreg(dst)
441*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[a].type) then
442*387f9dfdSAndroid Build Coastguard Worker			vderef(dst_reg, dst_reg, V[a])
443*387f9dfdSAndroid Build Coastguard Worker			V[dst].type = V[a].const.__dissector
444*387f9dfdSAndroid Build Coastguard Worker		else
445*387f9dfdSAndroid Build Coastguard Worker			V[dst].type = V[a].type
446*387f9dfdSAndroid Build Coastguard Worker		end
447*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF[op] + BPF.K, dst_reg, 0, 0, b)
448*387f9dfdSAndroid Build Coastguard Worker	end
449*387f9dfdSAndroid Build Coastguard Workerend
450*387f9dfdSAndroid Build Coastguard Worker
451*387f9dfdSAndroid Build Coastguard Workerlocal function ALU_REG(dst, a, b, op)
452*387f9dfdSAndroid Build Coastguard Worker	-- Fold compile-time expressions
453*387f9dfdSAndroid Build Coastguard Worker	if V[a].const and not (is_proxy(V[a].const) or is_proxy(V[b].const)) then
454*387f9dfdSAndroid Build Coastguard Worker		assert(cdef.isimmconst(V[a]), 'VAR '..a..' must be numeric')
455*387f9dfdSAndroid Build Coastguard Worker		assert(cdef.isimmconst(V[b]), 'VAR '..b..' must be numeric')
456*387f9dfdSAndroid Build Coastguard Worker		if type(op) == 'string' then op = const_expr[op] end
457*387f9dfdSAndroid Build Coastguard Worker		vcopy(dst, a)
458*387f9dfdSAndroid Build Coastguard Worker		V[dst].const = op(V[a].const, V[b].const)
459*387f9dfdSAndroid Build Coastguard Worker	else
460*387f9dfdSAndroid Build Coastguard Worker		local src_reg = b and vreg(b) or 0 -- SRC is optional for unary operations
461*387f9dfdSAndroid Build Coastguard Worker		if b and cdef.isptr(V[b].type) then
462*387f9dfdSAndroid Build Coastguard Worker			-- We have to allocate a temporary register for dereferencing to preserve
463*387f9dfdSAndroid Build Coastguard Worker			-- pointer in source variable that MUST NOT be altered
464*387f9dfdSAndroid Build Coastguard Worker			reg_alloc(stackslots, 2)
465*387f9dfdSAndroid Build Coastguard Worker			vderef(2, src_reg, V[b])
466*387f9dfdSAndroid Build Coastguard Worker			src_reg = 2
467*387f9dfdSAndroid Build Coastguard Worker		end
468*387f9dfdSAndroid Build Coastguard Worker		vcopy(dst, a) -- DST may alias B, so copy must occur after we materialize B
469*387f9dfdSAndroid Build Coastguard Worker		local dst_reg = vreg(dst)
470*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[a].type) then
471*387f9dfdSAndroid Build Coastguard Worker			vderef(dst_reg, dst_reg, V[a])
472*387f9dfdSAndroid Build Coastguard Worker			V[dst].type = V[a].const.__dissector
473*387f9dfdSAndroid Build Coastguard Worker		end
474*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF[op] + BPF.X, dst_reg, src_reg, 0, 0)
475*387f9dfdSAndroid Build Coastguard Worker		V[stackslots].reg = nil  -- Free temporary registers
476*387f9dfdSAndroid Build Coastguard Worker	end
477*387f9dfdSAndroid Build Coastguard Workerend
478*387f9dfdSAndroid Build Coastguard Worker
479*387f9dfdSAndroid Build Coastguard Workerlocal function ALU_IMM_NV(dst, a, b, op)
480*387f9dfdSAndroid Build Coastguard Worker	-- Do DST = IMM(a) op VAR(b) where we can't invert because
481*387f9dfdSAndroid Build Coastguard Worker	-- the registers are u64 but immediates are u32, so complement
482*387f9dfdSAndroid Build Coastguard Worker	-- arithmetics wouldn't work
483*387f9dfdSAndroid Build Coastguard Worker	vset(stackslots+1, nil, a)
484*387f9dfdSAndroid Build Coastguard Worker	ALU_REG(dst, stackslots+1, b, op)
485*387f9dfdSAndroid Build Coastguard Workerend
486*387f9dfdSAndroid Build Coastguard Worker
487*387f9dfdSAndroid Build Coastguard Workerlocal function LD_ABS(dst, w, off)
488*387f9dfdSAndroid Build Coastguard Worker	assert(off, 'LD_ABS called without offset')
489*387f9dfdSAndroid Build Coastguard Worker	if w < 8 then
490*387f9dfdSAndroid Build Coastguard Worker		local dst_reg = vreg(dst, 0, true, builtins.width_type(w)) -- Reserve R0
491*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.LD + BPF.ABS + const_width[w], dst_reg, 0, 0, off)
492*387f9dfdSAndroid Build Coastguard Worker		if w > 1 and ffi.abi('le') then -- LD_ABS has htonl() semantics, reverse
493*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU + BPF.END + BPF.TO_BE, dst_reg, 0, 0, w * 8)
494*387f9dfdSAndroid Build Coastguard Worker		end
495*387f9dfdSAndroid Build Coastguard Worker	elseif w == 8 then
496*387f9dfdSAndroid Build Coastguard Worker		-- LD_ABS|IND prohibits DW, we need to do two W loads and combine them
497*387f9dfdSAndroid Build Coastguard Worker		local tmp_reg = vreg(stackslots, 0, true, builtins.width_type(w)) -- Reserve R0
498*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.LD + BPF.ABS + const_width[4], tmp_reg, 0, 0, off + 4)
499*387f9dfdSAndroid Build Coastguard Worker		if ffi.abi('le') then -- LD_ABS has htonl() semantics, reverse
500*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU + BPF.END + BPF.TO_BE, tmp_reg, 0, 0, 32)
501*387f9dfdSAndroid Build Coastguard Worker		end
502*387f9dfdSAndroid Build Coastguard Worker		ALU_IMM(stackslots, stackslots, 32, 'LSH')
503*387f9dfdSAndroid Build Coastguard Worker		local dst_reg = vreg(dst, 0, true, builtins.width_type(w)) -- Reserve R0, spill tmp variable
504*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.LD + BPF.ABS + const_width[4], dst_reg, 0, 0, off)
505*387f9dfdSAndroid Build Coastguard Worker		if ffi.abi('le') then -- LD_ABS has htonl() semantics, reverse
506*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU + BPF.END + BPF.TO_BE, dst_reg, 0, 0, 32)
507*387f9dfdSAndroid Build Coastguard Worker		end
508*387f9dfdSAndroid Build Coastguard Worker		ALU_REG(dst, dst, stackslots, 'OR')
509*387f9dfdSAndroid Build Coastguard Worker		V[stackslots].reg = nil -- Free temporary registers
510*387f9dfdSAndroid Build Coastguard Worker	else
511*387f9dfdSAndroid Build Coastguard Worker		assert(w < 8, 'NYI: only LD_ABS of 1/2/4/8 is supported')
512*387f9dfdSAndroid Build Coastguard Worker	end
513*387f9dfdSAndroid Build Coastguard Workerend
514*387f9dfdSAndroid Build Coastguard Worker
515*387f9dfdSAndroid Build Coastguard Workerlocal function LD_IND(dst, src, w, off)
516*387f9dfdSAndroid Build Coastguard Worker	local src_reg = vreg(src) -- Must materialize first in case dst == src
517*387f9dfdSAndroid Build Coastguard Worker	local dst_reg = vreg(dst, 0, true, builtins.width_type(w)) -- Reserve R0
518*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.LD + BPF.IND + const_width[w], dst_reg, src_reg, 0, off or 0)
519*387f9dfdSAndroid Build Coastguard Worker	if w > 1 and ffi.abi('le') then -- LD_ABS has htonl() semantics, reverse
520*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU + BPF.END + BPF.TO_BE, dst_reg, 0, 0, w * 8)
521*387f9dfdSAndroid Build Coastguard Worker	end
522*387f9dfdSAndroid Build Coastguard Workerend
523*387f9dfdSAndroid Build Coastguard Worker
524*387f9dfdSAndroid Build Coastguard Workerlocal function LD_MEM(dst, src, w, off)
525*387f9dfdSAndroid Build Coastguard Worker	local src_reg = vreg(src) -- Must materialize first in case dst == src
526*387f9dfdSAndroid Build Coastguard Worker	local dst_reg = vreg(dst, nil, true, builtins.width_type(w)) -- Reserve R0
527*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.MEM + BPF.LDX + const_width[w], dst_reg, src_reg, off or 0, 0)
528*387f9dfdSAndroid Build Coastguard Workerend
529*387f9dfdSAndroid Build Coastguard Worker
530*387f9dfdSAndroid Build Coastguard Worker-- @note: This is specific now as it expects registers reserved
531*387f9dfdSAndroid Build Coastguard Workerlocal function LD_IMM_X(dst_reg, src_type, imm, w)
532*387f9dfdSAndroid Build Coastguard Worker	if w == 8 then -- IMM64 must be done in two instructions with imm64 = (lo(imm32), hi(imm32))
533*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.LD + const_width[w], dst_reg, src_type, 0, ffi.cast('uint32_t', imm))
534*387f9dfdSAndroid Build Coastguard Worker		-- Must shift in two steps as bit.lshift supports [0..31]
535*387f9dfdSAndroid Build Coastguard Worker		emit(0, 0, 0, 0, ffi.cast('uint32_t', bit.lshift(bit.lshift(imm, 16), 16)))
536*387f9dfdSAndroid Build Coastguard Worker	else
537*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.LD + const_width[w], dst_reg, src_type, 0, imm)
538*387f9dfdSAndroid Build Coastguard Worker	end
539*387f9dfdSAndroid Build Coastguard Workerend
540*387f9dfdSAndroid Build Coastguard Worker
541*387f9dfdSAndroid Build Coastguard Workerlocal function BUILTIN(func, ...)
542*387f9dfdSAndroid Build Coastguard Worker	local builtin_export = {
543*387f9dfdSAndroid Build Coastguard Worker		-- Compiler primitives (work with variable slots, emit instructions)
544*387f9dfdSAndroid Build Coastguard Worker		V=V, vreg=vreg, vset=vset, vcopy=vcopy, vderef=vderef, valloc=valloc, emit=emit,
545*387f9dfdSAndroid Build Coastguard Worker		reg_alloc=reg_alloc, reg_spill=reg_spill, tmpvar=stackslots, const_width=const_width,
546*387f9dfdSAndroid Build Coastguard Worker		-- Extensions and helpers (use with care)
547*387f9dfdSAndroid Build Coastguard Worker		LD_IMM_X = LD_IMM_X,
548*387f9dfdSAndroid Build Coastguard Worker	}
549*387f9dfdSAndroid Build Coastguard Worker	func(builtin_export, ...)
550*387f9dfdSAndroid Build Coastguard Workerend
551*387f9dfdSAndroid Build Coastguard Worker
552*387f9dfdSAndroid Build Coastguard Workerlocal function LOAD(dst, src, off, vtype)
553*387f9dfdSAndroid Build Coastguard Worker	local base = V[src].const
554*387f9dfdSAndroid Build Coastguard Worker	assert(base and base.__dissector, 'NYI: load() on variable that doesn\'t have dissector')
555*387f9dfdSAndroid Build Coastguard Worker	assert(V[src].source, 'NYI: load() on variable with unknown source')
556*387f9dfdSAndroid Build Coastguard Worker	-- Cast to different type if requested
557*387f9dfdSAndroid Build Coastguard Worker	vtype = vtype or base.__dissector
558*387f9dfdSAndroid Build Coastguard Worker	local w = ffi.sizeof(vtype)
559*387f9dfdSAndroid Build Coastguard Worker	assert(const_width[w], 'NYI: load() supports 1/2/4/8 bytes at a time only, wanted ' .. tostring(w))
560*387f9dfdSAndroid Build Coastguard Worker	-- Packet access with a dissector (use BPF_LD)
561*387f9dfdSAndroid Build Coastguard Worker	if V[src].source:find('ptr_to_pkt', 1, true) then
562*387f9dfdSAndroid Build Coastguard Worker		if base.off then -- Absolute address to payload
563*387f9dfdSAndroid Build Coastguard Worker			LD_ABS(dst, w, off + base.off)
564*387f9dfdSAndroid Build Coastguard Worker		else -- Indirect address to payload
565*387f9dfdSAndroid Build Coastguard Worker			LD_IND(dst, src, w, off)
566*387f9dfdSAndroid Build Coastguard Worker		end
567*387f9dfdSAndroid Build Coastguard Worker	-- Direct access to first argument (skb fields, pt regs, ...)
568*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].source:find('ptr_to_ctx', 1, true) then
569*387f9dfdSAndroid Build Coastguard Worker		LD_MEM(dst, src, w, off)
570*387f9dfdSAndroid Build Coastguard Worker	-- Direct skb access with a dissector (use BPF_MEM)
571*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].source:find('ptr_to_skb', 1, true) then
572*387f9dfdSAndroid Build Coastguard Worker		LD_MEM(dst, src, w, off)
573*387f9dfdSAndroid Build Coastguard Worker	-- Pointer to map-backed memory (use BPF_MEM)
574*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].source:find('ptr_to_map_value', 1, true) then
575*387f9dfdSAndroid Build Coastguard Worker		LD_MEM(dst, src, w, off)
576*387f9dfdSAndroid Build Coastguard Worker	-- Indirect read using probe (uprobe or kprobe, uses helper)
577*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].source:find('ptr_to_probe', 1, true) then
578*387f9dfdSAndroid Build Coastguard Worker		BUILTIN(builtins[builtins.probe_read], nil, dst, src, vtype, off)
579*387f9dfdSAndroid Build Coastguard Worker		V[dst].source = V[src].source -- Builtin handles everything
580*387f9dfdSAndroid Build Coastguard Worker	else
581*387f9dfdSAndroid Build Coastguard Worker		error('NYI: load() on variable from ' .. V[src].source)
582*387f9dfdSAndroid Build Coastguard Worker	end
583*387f9dfdSAndroid Build Coastguard Worker	V[dst].type = vtype
584*387f9dfdSAndroid Build Coastguard Worker	V[dst].const = nil -- Dissected value is not constant anymore
585*387f9dfdSAndroid Build Coastguard Workerend
586*387f9dfdSAndroid Build Coastguard Worker
587*387f9dfdSAndroid Build Coastguard Workerlocal function CALL(a, b, d)
588*387f9dfdSAndroid Build Coastguard Worker	assert(b-1 <= 1, 'NYI: CALL with >1 return values')
589*387f9dfdSAndroid Build Coastguard Worker	-- Perform either compile-time, helper, or builtin
590*387f9dfdSAndroid Build Coastguard Worker	local func = V[a].const
591*387f9dfdSAndroid Build Coastguard Worker	-- Gather all arguments and check if they're constant
592*387f9dfdSAndroid Build Coastguard Worker	local args, const, nargs = {}, true, d - 1
593*387f9dfdSAndroid Build Coastguard Worker	for i = a+1, a+d-1 do
594*387f9dfdSAndroid Build Coastguard Worker		table.insert(args, V[i].const)
595*387f9dfdSAndroid Build Coastguard Worker		if not V[i].const or is_proxy(V[i].const) then const = false end
596*387f9dfdSAndroid Build Coastguard Worker	end
597*387f9dfdSAndroid Build Coastguard Worker	local builtin = builtins[func]
598*387f9dfdSAndroid Build Coastguard Worker	if not const or nargs == 0 then
599*387f9dfdSAndroid Build Coastguard Worker		if builtin and type(builtin) == 'function' then
600*387f9dfdSAndroid Build Coastguard Worker			args = {a}
601*387f9dfdSAndroid Build Coastguard Worker			for i = a+1, a+nargs do table.insert(args, i) end
602*387f9dfdSAndroid Build Coastguard Worker			BUILTIN(builtin, unpack(args))
603*387f9dfdSAndroid Build Coastguard Worker		elseif V[a+2] and V[a+2].const then -- var OP imm
604*387f9dfdSAndroid Build Coastguard Worker			ALU_IMM(a, a+1, V[a+2].const, builtin)
605*387f9dfdSAndroid Build Coastguard Worker		elseif nargs <= 2 then              -- var OP var
606*387f9dfdSAndroid Build Coastguard Worker			ALU_REG(a, a+1, V[a+2] and a+2, builtin)
607*387f9dfdSAndroid Build Coastguard Worker		else
608*387f9dfdSAndroid Build Coastguard Worker			error('NYI: CALL non-builtin with 3 or more arguments')
609*387f9dfdSAndroid Build Coastguard Worker		end
610*387f9dfdSAndroid Build Coastguard Worker	-- Call on dissector implies slice retrieval
611*387f9dfdSAndroid Build Coastguard Worker	elseif type(func) == 'table' and func.__dissector then
612*387f9dfdSAndroid Build Coastguard Worker		assert(nargs >= 2, 'NYI: <dissector>.slice(a, b) must have at least two arguments')
613*387f9dfdSAndroid Build Coastguard Worker		assert(V[a+1].const and V[a+2].const, 'NYI: slice() arguments must be constant')
614*387f9dfdSAndroid Build Coastguard Worker		local off = V[a+1].const
615*387f9dfdSAndroid Build Coastguard Worker		local vtype = builtins.width_type(V[a+2].const - off)
616*387f9dfdSAndroid Build Coastguard Worker		-- Access to packet via packet (use BPF_LD)
617*387f9dfdSAndroid Build Coastguard Worker		if V[a].source and V[a].source:find('ptr_to_', 1, true) then
618*387f9dfdSAndroid Build Coastguard Worker			LOAD(a, a, off, vtype)
619*387f9dfdSAndroid Build Coastguard Worker		else
620*387f9dfdSAndroid Build Coastguard Worker			error('NYI: <dissector>.slice(a, b) on non-pointer memory ' .. (V[a].source or 'unknown'))
621*387f9dfdSAndroid Build Coastguard Worker		end
622*387f9dfdSAndroid Build Coastguard Worker	-- Strict builtins cannot be expanded on compile-time
623*387f9dfdSAndroid Build Coastguard Worker	elseif builtins_strict[func] and builtin then
624*387f9dfdSAndroid Build Coastguard Worker		args = {a}
625*387f9dfdSAndroid Build Coastguard Worker		for i = a+1, a+nargs do table.insert(args, i) end
626*387f9dfdSAndroid Build Coastguard Worker		BUILTIN(builtin, unpack(args))
627*387f9dfdSAndroid Build Coastguard Worker	-- Attempt compile-time call expansion (expects all argument compile-time known)
628*387f9dfdSAndroid Build Coastguard Worker	else
629*387f9dfdSAndroid Build Coastguard Worker		assert(const, 'NYI: CALL attempted on constant arguments, but at least one argument is not constant')
630*387f9dfdSAndroid Build Coastguard Worker		V[a].const = func(unpack(args))
631*387f9dfdSAndroid Build Coastguard Worker	end
632*387f9dfdSAndroid Build Coastguard Workerend
633*387f9dfdSAndroid Build Coastguard Worker
634*387f9dfdSAndroid Build Coastguard Workerlocal function MAP_INIT(map_var, key, imm)
635*387f9dfdSAndroid Build Coastguard Worker	local map = V[map_var].const
636*387f9dfdSAndroid Build Coastguard Worker	vreg(map_var, 1, true, ffi.typeof('uint64_t'))
637*387f9dfdSAndroid Build Coastguard Worker	-- Reserve R1 and load ptr for process-local map fd
638*387f9dfdSAndroid Build Coastguard Worker	LD_IMM_X(1, BPF.PSEUDO_MAP_FD, map.fd, ffi.sizeof(V[map_var].type))
639*387f9dfdSAndroid Build Coastguard Worker	V[map_var].reg = nil -- R1 will be invalidated after CALL, forget register allocation
640*387f9dfdSAndroid Build Coastguard Worker	-- Reserve R2 and load R2 = key pointer
641*387f9dfdSAndroid Build Coastguard Worker	local key_size = ffi.sizeof(map.key_type)
642*387f9dfdSAndroid Build Coastguard Worker	local w = const_width[key_size] or BPF.DW
643*387f9dfdSAndroid Build Coastguard Worker	local pod_type = const_width[key_size]
644*387f9dfdSAndroid Build Coastguard Worker	local sp = stack_top + key_size -- Must use stack below spill slots
645*387f9dfdSAndroid Build Coastguard Worker	-- Store immediate value on stack
646*387f9dfdSAndroid Build Coastguard Worker	reg_alloc(stackslots, 2) -- Spill anything in R2 (unnamed tmp variable)
647*387f9dfdSAndroid Build Coastguard Worker	local key_base = key and V[key].const
648*387f9dfdSAndroid Build Coastguard Worker	imm = imm or key_base
649*387f9dfdSAndroid Build Coastguard Worker	if imm and (not key or not is_proxy(key_base)) then
650*387f9dfdSAndroid Build Coastguard Worker		assert(pod_type, 'NYI: map[const K], K width must be 1/2/4/8')
651*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.MEM + BPF.ST + w, 10, 0, -sp, imm)
652*387f9dfdSAndroid Build Coastguard Worker	-- Key is in register, spill it
653*387f9dfdSAndroid Build Coastguard Worker	elseif V[key].reg and pod_type then
654*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[key].type) then
655*387f9dfdSAndroid Build Coastguard Worker			-- There is already pointer in register, dereference before spilling
656*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.LDX + w, 2, V[key].reg, 0, 0)
657*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.STX + w, 10, 2, -sp, 0)
658*387f9dfdSAndroid Build Coastguard Worker		else -- Variable in register is POD, spill it on the stack
659*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.STX + w, 10, V[key].reg, -sp, 0)
660*387f9dfdSAndroid Build Coastguard Worker		end
661*387f9dfdSAndroid Build Coastguard Worker	-- Key is spilled from register to stack
662*387f9dfdSAndroid Build Coastguard Worker	elseif V[key].spill then
663*387f9dfdSAndroid Build Coastguard Worker		sp = V[key].spill
664*387f9dfdSAndroid Build Coastguard Worker	-- Key is already on stack, write to base-relative address
665*387f9dfdSAndroid Build Coastguard Worker	elseif key_base.__base then
666*387f9dfdSAndroid Build Coastguard Worker		assert(key_size == ffi.sizeof(V[key].type), 'VAR '..key..' type incompatible with BPF map key type')
667*387f9dfdSAndroid Build Coastguard Worker		sp = key_base.__base
668*387f9dfdSAndroid Build Coastguard Worker	else
669*387f9dfdSAndroid Build Coastguard Worker		error('VAR '..key..' is neither const-expr/register/stack/spilled')
670*387f9dfdSAndroid Build Coastguard Worker	end
671*387f9dfdSAndroid Build Coastguard Worker	-- If [FP+K] addressing, emit it
672*387f9dfdSAndroid Build Coastguard Worker	if sp then
673*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.MOV + BPF.X, 2, 10, 0, 0)
674*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.ADD + BPF.K, 2, 0, 0, -sp)
675*387f9dfdSAndroid Build Coastguard Worker	end
676*387f9dfdSAndroid Build Coastguard Workerend
677*387f9dfdSAndroid Build Coastguard Worker
678*387f9dfdSAndroid Build Coastguard Workerlocal function MAP_GET(dst, map_var, key, imm)
679*387f9dfdSAndroid Build Coastguard Worker	local map = V[map_var].const
680*387f9dfdSAndroid Build Coastguard Worker	MAP_INIT(map_var, key, imm)
681*387f9dfdSAndroid Build Coastguard Worker	-- Flag as pointer type and associate dissector for map value type
682*387f9dfdSAndroid Build Coastguard Worker	vreg(dst, 0, true, ffi.typeof('uint8_t *'))
683*387f9dfdSAndroid Build Coastguard Worker	V[dst].const = {__dissector=map.val_type}
684*387f9dfdSAndroid Build Coastguard Worker	V[dst].source = 'ptr_to_map_value_or_null'
685*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.JMP + BPF.CALL, 0, 0, 0, HELPER.map_lookup_elem)
686*387f9dfdSAndroid Build Coastguard Worker	V[stackslots].reg = nil -- Free temporary registers
687*387f9dfdSAndroid Build Coastguard Workerend
688*387f9dfdSAndroid Build Coastguard Worker
689*387f9dfdSAndroid Build Coastguard Workerlocal function MAP_DEL(map_var, key, key_imm)
690*387f9dfdSAndroid Build Coastguard Worker	-- Set R0, R1 (map fd, preempt R0)
691*387f9dfdSAndroid Build Coastguard Worker	reg_alloc(stackslots, 0) -- Spill anything in R0 (unnamed tmp variable)
692*387f9dfdSAndroid Build Coastguard Worker	MAP_INIT(map_var, key, key_imm)
693*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.JMP + BPF.CALL, 0, 0, 0, HELPER.map_delete_elem)
694*387f9dfdSAndroid Build Coastguard Worker	V[stackslots].reg = nil -- Free temporary registers
695*387f9dfdSAndroid Build Coastguard Workerend
696*387f9dfdSAndroid Build Coastguard Worker
697*387f9dfdSAndroid Build Coastguard Workerlocal function MAP_SET(map_var, key, key_imm, src)
698*387f9dfdSAndroid Build Coastguard Worker	local map = V[map_var].const
699*387f9dfdSAndroid Build Coastguard Worker	-- Delete when setting nil
700*387f9dfdSAndroid Build Coastguard Worker	if V[src].type == ffi.typeof('void') then
701*387f9dfdSAndroid Build Coastguard Worker		return MAP_DEL(map_var, key, key_imm)
702*387f9dfdSAndroid Build Coastguard Worker	end
703*387f9dfdSAndroid Build Coastguard Worker	-- Set R0, R1 (map fd, preempt R0)
704*387f9dfdSAndroid Build Coastguard Worker	reg_alloc(stackslots, 0) -- Spill anything in R0 (unnamed tmp variable)
705*387f9dfdSAndroid Build Coastguard Worker	MAP_INIT(map_var, key, key_imm)
706*387f9dfdSAndroid Build Coastguard Worker	reg_alloc(stackslots, 4) -- Spill anything in R4 (unnamed tmp variable)
707*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.ALU64 + BPF.MOV + BPF.K, 4, 0, 0, 0) -- BPF_ANY, create new element or update existing
708*387f9dfdSAndroid Build Coastguard Worker	-- Reserve R3 for value pointer
709*387f9dfdSAndroid Build Coastguard Worker	reg_alloc(stackslots, 3) -- Spill anything in R3 (unnamed tmp variable)
710*387f9dfdSAndroid Build Coastguard Worker	local val_size = ffi.sizeof(map.val_type)
711*387f9dfdSAndroid Build Coastguard Worker	local w = const_width[val_size] or BPF.DW
712*387f9dfdSAndroid Build Coastguard Worker	local pod_type = const_width[val_size]
713*387f9dfdSAndroid Build Coastguard Worker	-- Stack pointer must be aligned to both key/value size and have enough headroom for (key, value)
714*387f9dfdSAndroid Build Coastguard Worker	local sp = stack_top + ffi.sizeof(map.key_type) + val_size
715*387f9dfdSAndroid Build Coastguard Worker	sp = sp + (sp % val_size)
716*387f9dfdSAndroid Build Coastguard Worker	local base = V[src].const
717*387f9dfdSAndroid Build Coastguard Worker	if base and not is_proxy(base) then
718*387f9dfdSAndroid Build Coastguard Worker		assert(pod_type, 'NYI: MAP[K] = imm V; V width must be 1/2/4/8')
719*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.MEM + BPF.ST + w, 10, 0, -sp, base)
720*387f9dfdSAndroid Build Coastguard Worker	-- Value is in register, spill it
721*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].reg and pod_type then
722*387f9dfdSAndroid Build Coastguard Worker		-- Value is a pointer, derefernce it and spill it
723*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[src].type) then
724*387f9dfdSAndroid Build Coastguard Worker			vderef(3, V[src].reg, V[src])
725*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.STX + w, 10, 3, -sp, 0)
726*387f9dfdSAndroid Build Coastguard Worker		else
727*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.STX + w, 10, V[src].reg, -sp, 0)
728*387f9dfdSAndroid Build Coastguard Worker		end
729*387f9dfdSAndroid Build Coastguard Worker	-- We get a pointer to spilled register on stack
730*387f9dfdSAndroid Build Coastguard Worker	elseif V[src].spill then
731*387f9dfdSAndroid Build Coastguard Worker		-- If variable is a pointer, we can load it to R3 directly (save "LEA")
732*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[src].type) then
733*387f9dfdSAndroid Build Coastguard Worker			reg_fill(src, 3)
734*387f9dfdSAndroid Build Coastguard Worker			-- If variable is a stack pointer, we don't have to check it
735*387f9dfdSAndroid Build Coastguard Worker			if base.__base then
736*387f9dfdSAndroid Build Coastguard Worker				emit(BPF.JMP + BPF.CALL, 0, 0, 0, HELPER.map_update_elem)
737*387f9dfdSAndroid Build Coastguard Worker				return
738*387f9dfdSAndroid Build Coastguard Worker			end
739*387f9dfdSAndroid Build Coastguard Worker			vderef(3, V[src].reg, V[src])
740*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.MEM + BPF.STX + w, 10, 3, -sp, 0)
741*387f9dfdSAndroid Build Coastguard Worker		else
742*387f9dfdSAndroid Build Coastguard Worker			sp = V[src].spill
743*387f9dfdSAndroid Build Coastguard Worker		end
744*387f9dfdSAndroid Build Coastguard Worker	-- Value is already on stack, write to base-relative address
745*387f9dfdSAndroid Build Coastguard Worker	elseif base.__base then
746*387f9dfdSAndroid Build Coastguard Worker		if val_size ~= ffi.sizeof(V[src].type) then
747*387f9dfdSAndroid Build Coastguard Worker			local err = string.format('VAR %d type (%s) incompatible with BPF map value type (%s): expected %d, got %d',
748*387f9dfdSAndroid Build Coastguard Worker				src, V[src].type, map.val_type, val_size, ffi.sizeof(V[src].type))
749*387f9dfdSAndroid Build Coastguard Worker			error(err)
750*387f9dfdSAndroid Build Coastguard Worker		end
751*387f9dfdSAndroid Build Coastguard Worker		sp = base.__base
752*387f9dfdSAndroid Build Coastguard Worker	-- Value is constant, materialize it on stack
753*387f9dfdSAndroid Build Coastguard Worker	else
754*387f9dfdSAndroid Build Coastguard Worker		error('VAR '.. src ..' is neither const-expr/register/stack/spilled')
755*387f9dfdSAndroid Build Coastguard Worker	end
756*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.ALU64 + BPF.MOV + BPF.X, 3, 10, 0, 0)
757*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.ALU64 + BPF.ADD + BPF.K, 3, 0, 0, -sp)
758*387f9dfdSAndroid Build Coastguard Worker	emit(BPF.JMP + BPF.CALL, 0, 0, 0, HELPER.map_update_elem)
759*387f9dfdSAndroid Build Coastguard Worker	V[stackslots].reg = nil -- Free temporary registers
760*387f9dfdSAndroid Build Coastguard Workerend
761*387f9dfdSAndroid Build Coastguard Worker
762*387f9dfdSAndroid Build Coastguard Worker-- Finally - this table translates LuaJIT bytecode into code emitter actions.
763*387f9dfdSAndroid Build Coastguard Workerlocal BC = {
764*387f9dfdSAndroid Build Coastguard Worker	-- Constants
765*387f9dfdSAndroid Build Coastguard Worker	KNUM = function(a, _, c, _) -- KNUM
766*387f9dfdSAndroid Build Coastguard Worker		if c < 2147483648 then
767*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, c, ffi.typeof('int32_t'))
768*387f9dfdSAndroid Build Coastguard Worker		else
769*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, c, ffi.typeof('uint64_t'))
770*387f9dfdSAndroid Build Coastguard Worker		end
771*387f9dfdSAndroid Build Coastguard Worker	end,
772*387f9dfdSAndroid Build Coastguard Worker	KSHORT = function(a, _, _, d) -- KSHORT
773*387f9dfdSAndroid Build Coastguard Worker		vset(a, nil, d, ffi.typeof('int16_t'))
774*387f9dfdSAndroid Build Coastguard Worker	end,
775*387f9dfdSAndroid Build Coastguard Worker	KCDATA = function(a, _, c, _) -- KCDATA
776*387f9dfdSAndroid Build Coastguard Worker		-- Coerce numeric types if possible
777*387f9dfdSAndroid Build Coastguard Worker		local ct = ffi.typeof(c)
778*387f9dfdSAndroid Build Coastguard Worker		if ffi.istype(ct, ffi.typeof('uint64_t')) or ffi.istype(ct, ffi.typeof('int64_t')) then
779*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, c, ct)
780*387f9dfdSAndroid Build Coastguard Worker		elseif tonumber(c) ~= nil then
781*387f9dfdSAndroid Build Coastguard Worker			-- TODO: this should not be possible
782*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, tonumber(c), ct)
783*387f9dfdSAndroid Build Coastguard Worker		else
784*387f9dfdSAndroid Build Coastguard Worker			error('NYI: cannot use CDATA constant of type ' .. ct)
785*387f9dfdSAndroid Build Coastguard Worker		end
786*387f9dfdSAndroid Build Coastguard Worker	end,
787*387f9dfdSAndroid Build Coastguard Worker	KPRI = function(a, _, _, d) -- KPRI
788*387f9dfdSAndroid Build Coastguard Worker		-- KNIL is 0, must create a special type to identify it
789*387f9dfdSAndroid Build Coastguard Worker		local vtype = (d < 1) and ffi.typeof('void') or ffi.typeof('uint8_t')
790*387f9dfdSAndroid Build Coastguard Worker		vset(a, nil, (d < 2) and 0 or 1, vtype)
791*387f9dfdSAndroid Build Coastguard Worker	end,
792*387f9dfdSAndroid Build Coastguard Worker	KSTR = function(a, _, c, _) -- KSTR
793*387f9dfdSAndroid Build Coastguard Worker		vset(a, nil, c, ffi.typeof('const char[?]'))
794*387f9dfdSAndroid Build Coastguard Worker	end,
795*387f9dfdSAndroid Build Coastguard Worker	MOV = function(a, _, _, d) -- MOV var, var
796*387f9dfdSAndroid Build Coastguard Worker		vcopy(a, d)
797*387f9dfdSAndroid Build Coastguard Worker	end,
798*387f9dfdSAndroid Build Coastguard Worker
799*387f9dfdSAndroid Build Coastguard Worker	-- Comparison ops
800*387f9dfdSAndroid Build Coastguard Worker	-- Note: comparisons are always followed by JMP opcode, that
801*387f9dfdSAndroid Build Coastguard Worker	--       will fuse following JMP to JMP+CMP instruction in BPF
802*387f9dfdSAndroid Build Coastguard Worker	-- Note:  we're narrowed to integers, so operand/operator inversion is legit
803*387f9dfdSAndroid Build Coastguard Worker	ISLT = function(a, _, _, d) return CMP_REG(d, a, 'JGE') end, -- (a < d) (inverted)
804*387f9dfdSAndroid Build Coastguard Worker	ISGE = function(a, _, _, d) return CMP_REG(a, d, 'JGE') end, -- (a >= d)
805*387f9dfdSAndroid Build Coastguard Worker	ISGT = function(a, _, _, d) return CMP_REG(a, d, 'JGT') end, -- (a > d)
806*387f9dfdSAndroid Build Coastguard Worker	ISEQV = function(a, _, _, d) return CMP_REG(a, d, 'JEQ') end, -- (a == d)
807*387f9dfdSAndroid Build Coastguard Worker	ISNEV = function(a, _, _, d) return CMP_REG(a, d, 'JNE') end, -- (a ~= d)
808*387f9dfdSAndroid Build Coastguard Worker	ISEQS = function(a, _, c, _) return CMP_IMM(a, c, 'JEQ') end, -- (a == str(c))
809*387f9dfdSAndroid Build Coastguard Worker	ISNES = function(a, _, c, _) return CMP_IMM(a, c, 'JNE') end, -- (a ~= str(c))
810*387f9dfdSAndroid Build Coastguard Worker	ISEQN = function(a, _, c, _) return CMP_IMM(a, c, 'JEQ') end, -- (a == c)
811*387f9dfdSAndroid Build Coastguard Worker	ISNEN = function(a, _, c, _) return CMP_IMM(a, c, 'JNE') end, -- (a ~= c)
812*387f9dfdSAndroid Build Coastguard Worker	IST = function(_, _, _, d) return CMP_IMM(d, 0, 'JNE') end, -- (d)
813*387f9dfdSAndroid Build Coastguard Worker	ISF = function(_, _, _, d) return CMP_IMM(d, 0, 'JEQ') end, -- (not d)
814*387f9dfdSAndroid Build Coastguard Worker	ISEQP = function(a, _, c, _) return CMP_IMM(a, c, 'JEQ') end, -- ISEQP (a == c)
815*387f9dfdSAndroid Build Coastguard Worker	-- Binary operations with RHS constants
816*387f9dfdSAndroid Build Coastguard Worker	ADDVN = function(a, b, c, _) return ALU_IMM(a, b, c, 'ADD') end,
817*387f9dfdSAndroid Build Coastguard Worker	SUBVN = function(a, b, c, _) return ALU_IMM(a, b, c, 'SUB') end,
818*387f9dfdSAndroid Build Coastguard Worker	MULVN = function(a, b, c, _) return ALU_IMM(a, b, c, 'MUL') end,
819*387f9dfdSAndroid Build Coastguard Worker	DIVVN = function(a, b, c, _) return ALU_IMM(a, b, c, 'DIV') end,
820*387f9dfdSAndroid Build Coastguard Worker	MODVN = function(a, b, c, _) return ALU_IMM(a, b, c, 'MOD') end,
821*387f9dfdSAndroid Build Coastguard Worker	-- Binary operations with LHS constants
822*387f9dfdSAndroid Build Coastguard Worker	-- Cheat code: we're narrowed to integer arithmetic, so MUL+ADD are commutative
823*387f9dfdSAndroid Build Coastguard Worker	ADDNV = function(a, b, c, _) return ALU_IMM(a, b, c, 'ADD') end, -- ADDNV
824*387f9dfdSAndroid Build Coastguard Worker	MULNV = function(a, b, c, _) return ALU_IMM(a, b, c, 'MUL') end, -- MULNV
825*387f9dfdSAndroid Build Coastguard Worker	SUBNV = function(a, b, c, _) return ALU_IMM_NV(a, c, b, 'SUB') end, -- SUBNV
826*387f9dfdSAndroid Build Coastguard Worker	DIVNV = function(a, b, c, _) return ALU_IMM_NV(a, c, b, 'DIV') end, -- DIVNV
827*387f9dfdSAndroid Build Coastguard Worker	-- Binary operations between registers
828*387f9dfdSAndroid Build Coastguard Worker	ADDVV = function(a, b, _, d) return ALU_REG(a, b, d, 'ADD') end,
829*387f9dfdSAndroid Build Coastguard Worker	SUBVV = function(a, b, _, d) return ALU_REG(a, b, d, 'SUB') end,
830*387f9dfdSAndroid Build Coastguard Worker	MULVV = function(a, b, _, d) return ALU_REG(a, b, d, 'MUL') end,
831*387f9dfdSAndroid Build Coastguard Worker	DIVVV = function(a, b, _, d) return ALU_REG(a, b, d, 'DIV') end,
832*387f9dfdSAndroid Build Coastguard Worker	MODVV = function(a, b, _, d) return ALU_REG(a, b, d, 'MOD') end,
833*387f9dfdSAndroid Build Coastguard Worker	-- Strings
834*387f9dfdSAndroid Build Coastguard Worker	CAT = function(a, b, _, d) -- CAT A = B ~ D
835*387f9dfdSAndroid Build Coastguard Worker		assert(V[b].const and V[d].const, 'NYI: CAT only works on compile-time expressions')
836*387f9dfdSAndroid Build Coastguard Worker		assert(type(V[b].const) == 'string' and type(V[d].const) == 'string',
837*387f9dfdSAndroid Build Coastguard Worker			'NYI: CAT only works on compile-time strings')
838*387f9dfdSAndroid Build Coastguard Worker		vset(a, nil, V[b].const .. V[d].const)
839*387f9dfdSAndroid Build Coastguard Worker	end,
840*387f9dfdSAndroid Build Coastguard Worker	-- Tables
841*387f9dfdSAndroid Build Coastguard Worker	GGET = function (a, _, c, _) -- GGET (A = GLOBAL[c])
842*387f9dfdSAndroid Build Coastguard Worker		if env[c] ~= nil then
843*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, env[c])
844*387f9dfdSAndroid Build Coastguard Worker		else error(string.format("undefined global '%s'", c)) end
845*387f9dfdSAndroid Build Coastguard Worker	end,
846*387f9dfdSAndroid Build Coastguard Worker	UGET = function (a, _, c, _) -- UGET (A = UPVALUE[c])
847*387f9dfdSAndroid Build Coastguard Worker		if env[c] ~= nil then
848*387f9dfdSAndroid Build Coastguard Worker			vset(a, nil, env[c])
849*387f9dfdSAndroid Build Coastguard Worker		else error(string.format("undefined upvalue '%s'", c)) end
850*387f9dfdSAndroid Build Coastguard Worker	end,
851*387f9dfdSAndroid Build Coastguard Worker	TSETB = function (a, b, _, d) -- TSETB (B[D] = A)
852*387f9dfdSAndroid Build Coastguard Worker		assert(V[b] and type(V[b].const) == 'table', 'NYI: B[D] where B is not Lua table, BPF map, or pointer')
853*387f9dfdSAndroid Build Coastguard Worker		local vinfo = V[b].const
854*387f9dfdSAndroid Build Coastguard Worker		if vinfo.__map then -- BPF map read (constant)
855*387f9dfdSAndroid Build Coastguard Worker			return MAP_SET(b, nil, d, a) -- D is literal
856*387f9dfdSAndroid Build Coastguard Worker		elseif vinfo.__dissector then
857*387f9dfdSAndroid Build Coastguard Worker			assert(vinfo.__dissector, 'NYI: B[D] where B does not have a known element size')
858*387f9dfdSAndroid Build Coastguard Worker			local w = ffi.sizeof(vinfo.__dissector)
859*387f9dfdSAndroid Build Coastguard Worker			-- TODO: support vectorized moves larger than register width
860*387f9dfdSAndroid Build Coastguard Worker			assert(const_width[w], 'B[C] = A, sizeof(A) must be 1/2/4/8')
861*387f9dfdSAndroid Build Coastguard Worker			local src_reg, const = vscalar(a, w)
862*387f9dfdSAndroid Build Coastguard Worker			-- If changing map value, write to absolute address + offset
863*387f9dfdSAndroid Build Coastguard Worker			if V[b].source and V[b].source:find('ptr_to_map_value', 1, true) then
864*387f9dfdSAndroid Build Coastguard Worker				local dst_reg = vreg(b)
865*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
866*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' then
867*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], dst_reg, 0, d, const)
868*387f9dfdSAndroid Build Coastguard Worker				else
869*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], dst_reg, src_reg, d, 0)
870*387f9dfdSAndroid Build Coastguard Worker				end
871*387f9dfdSAndroid Build Coastguard Worker			-- Table is already on stack, write to vinfo-relative address
872*387f9dfdSAndroid Build Coastguard Worker			elseif vinfo.__base then
873*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
874*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' then
875*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], 10, 0, -vinfo.__base + (d * w), const)
876*387f9dfdSAndroid Build Coastguard Worker				else
877*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], 10, src_reg, -vinfo.__base + (d * w), 0)
878*387f9dfdSAndroid Build Coastguard Worker				end
879*387f9dfdSAndroid Build Coastguard Worker			else
880*387f9dfdSAndroid Build Coastguard Worker				error('NYI: B[D] where B is not Lua table, BPF map, or pointer')
881*387f9dfdSAndroid Build Coastguard Worker			end
882*387f9dfdSAndroid Build Coastguard Worker		elseif vinfo and vinfo and V[a].const then
883*387f9dfdSAndroid Build Coastguard Worker			vinfo[V[d].const] = V[a].const
884*387f9dfdSAndroid Build Coastguard Worker		else
885*387f9dfdSAndroid Build Coastguard Worker			error('NYI: B[D] where B is not Lua table, BPF map, or pointer')
886*387f9dfdSAndroid Build Coastguard Worker		end
887*387f9dfdSAndroid Build Coastguard Worker	end,
888*387f9dfdSAndroid Build Coastguard Worker	TSETV = function (a, b, _, d) -- TSETV (B[D] = A)
889*387f9dfdSAndroid Build Coastguard Worker		assert(V[b] and type(V[b].const) == 'table', 'NYI: B[D] where B is not Lua table, BPF map, or pointer')
890*387f9dfdSAndroid Build Coastguard Worker		local vinfo = V[b].const
891*387f9dfdSAndroid Build Coastguard Worker		if vinfo.__map then -- BPF map read (constant)
892*387f9dfdSAndroid Build Coastguard Worker			return MAP_SET(b, d, nil, a) -- D is variable
893*387f9dfdSAndroid Build Coastguard Worker		elseif vinfo.__dissector then
894*387f9dfdSAndroid Build Coastguard Worker			assert(vinfo.__dissector, 'NYI: B[D] where B does not have a known element size')
895*387f9dfdSAndroid Build Coastguard Worker			local w = ffi.sizeof(vinfo.__dissector)
896*387f9dfdSAndroid Build Coastguard Worker			-- TODO: support vectorized moves larger than register width
897*387f9dfdSAndroid Build Coastguard Worker			assert(const_width[w], 'B[C] = A, sizeof(A) must be 1/2/4/8')
898*387f9dfdSAndroid Build Coastguard Worker			local src_reg, const = vscalar(a, w)
899*387f9dfdSAndroid Build Coastguard Worker			-- If changing map value, write to absolute address + offset
900*387f9dfdSAndroid Build Coastguard Worker			if V[b].source and V[b].source:find('ptr_to_map_value', 1, true) then
901*387f9dfdSAndroid Build Coastguard Worker				-- Calculate variable address from two registers
902*387f9dfdSAndroid Build Coastguard Worker				local tmp_var = stackslots + 1
903*387f9dfdSAndroid Build Coastguard Worker				vset(tmp_var, nil, d)
904*387f9dfdSAndroid Build Coastguard Worker				ALU_REG(tmp_var, tmp_var, b, 'ADD')
905*387f9dfdSAndroid Build Coastguard Worker				local dst_reg = vreg(tmp_var)
906*387f9dfdSAndroid Build Coastguard Worker				V[tmp_var].reg = nil -- Only temporary allocation
907*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
908*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' and w < 8 then
909*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], dst_reg, 0, 0, const)
910*387f9dfdSAndroid Build Coastguard Worker				else
911*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], dst_reg, src_reg, 0, 0)
912*387f9dfdSAndroid Build Coastguard Worker				end
913*387f9dfdSAndroid Build Coastguard Worker			-- Table is already on stack, write to vinfo-relative address
914*387f9dfdSAndroid Build Coastguard Worker			elseif vinfo.__base then
915*387f9dfdSAndroid Build Coastguard Worker				-- Calculate variable address from two registers
916*387f9dfdSAndroid Build Coastguard Worker				local tmp_var = stackslots + 1
917*387f9dfdSAndroid Build Coastguard Worker				vcopy(tmp_var, d)                       -- Element position
918*387f9dfdSAndroid Build Coastguard Worker				if w > 1 then
919*387f9dfdSAndroid Build Coastguard Worker					ALU_IMM(tmp_var, tmp_var, w, 'MUL') -- multiply by element size
920*387f9dfdSAndroid Build Coastguard Worker				end
921*387f9dfdSAndroid Build Coastguard Worker				local dst_reg = vreg(tmp_var)           -- add R10 (stack pointer)
922*387f9dfdSAndroid Build Coastguard Worker				emit(BPF.ALU64 + BPF.ADD + BPF.X, dst_reg, 10, 0, 0)
923*387f9dfdSAndroid Build Coastguard Worker				V[tmp_var].reg = nil -- Only temporary allocation
924*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
925*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' and w < 8 then
926*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], dst_reg, 0, -vinfo.__base, const)
927*387f9dfdSAndroid Build Coastguard Worker				else
928*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], dst_reg, src_reg, -vinfo.__base, 0)
929*387f9dfdSAndroid Build Coastguard Worker				end
930*387f9dfdSAndroid Build Coastguard Worker			else
931*387f9dfdSAndroid Build Coastguard Worker				error('NYI: B[D] where B is not Lua table, BPF map, or pointer')
932*387f9dfdSAndroid Build Coastguard Worker			end
933*387f9dfdSAndroid Build Coastguard Worker		elseif vinfo and V[d].const and V[a].const then
934*387f9dfdSAndroid Build Coastguard Worker			vinfo[V[d].const] = V[a].const
935*387f9dfdSAndroid Build Coastguard Worker		else
936*387f9dfdSAndroid Build Coastguard Worker			error('NYI: B[D] where B is not Lua table, BPF map, or pointer')
937*387f9dfdSAndroid Build Coastguard Worker		end
938*387f9dfdSAndroid Build Coastguard Worker	end,
939*387f9dfdSAndroid Build Coastguard Worker	TSETS = function (a, b, c, _) -- TSETS (B[C] = A)
940*387f9dfdSAndroid Build Coastguard Worker		assert(V[b] and V[b].const, 'NYI: B[D] where B is not Lua table, BPF map, or pointer')
941*387f9dfdSAndroid Build Coastguard Worker		local base = V[b].const
942*387f9dfdSAndroid Build Coastguard Worker		if base.__dissector then
943*387f9dfdSAndroid Build Coastguard Worker			local ofs,bpos = ffi.offsetof(base.__dissector, c)
944*387f9dfdSAndroid Build Coastguard Worker			assert(not bpos, 'NYI: B[C] = A, where C is a bitfield')
945*387f9dfdSAndroid Build Coastguard Worker			local w = builtins.sizeofattr(base.__dissector, c)
946*387f9dfdSAndroid Build Coastguard Worker			-- TODO: support vectorized moves larger than register width
947*387f9dfdSAndroid Build Coastguard Worker			assert(const_width[w], 'B[C] = A, sizeof(A) must be 1/2/4/8')
948*387f9dfdSAndroid Build Coastguard Worker			local src_reg, const = vscalar(a, w)
949*387f9dfdSAndroid Build Coastguard Worker			-- If changing map value, write to absolute address + offset
950*387f9dfdSAndroid Build Coastguard Worker			if V[b].source and V[b].source:find('ptr_to_map_value', 1, true) then
951*387f9dfdSAndroid Build Coastguard Worker				local dst_reg = vreg(b)
952*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
953*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' and w < 8 then
954*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], dst_reg, 0, ofs, const)
955*387f9dfdSAndroid Build Coastguard Worker				else
956*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], dst_reg, src_reg, ofs, 0)
957*387f9dfdSAndroid Build Coastguard Worker				end
958*387f9dfdSAndroid Build Coastguard Worker			-- Table is already on stack, write to base-relative address
959*387f9dfdSAndroid Build Coastguard Worker			elseif base.__base then
960*387f9dfdSAndroid Build Coastguard Worker				-- Optimization: immediate values (imm32) can be stored directly
961*387f9dfdSAndroid Build Coastguard Worker				if type(const) == 'number' and w < 8 then
962*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.ST + const_width[w], 10, 0, -base.__base + ofs, const)
963*387f9dfdSAndroid Build Coastguard Worker				else
964*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.MEM + BPF.STX + const_width[w], 10, src_reg, -base.__base + ofs, 0)
965*387f9dfdSAndroid Build Coastguard Worker				end
966*387f9dfdSAndroid Build Coastguard Worker			else
967*387f9dfdSAndroid Build Coastguard Worker				error('NYI: B[C] where B is not Lua table, BPF map, or pointer')
968*387f9dfdSAndroid Build Coastguard Worker			end
969*387f9dfdSAndroid Build Coastguard Worker		elseif V[a].const then
970*387f9dfdSAndroid Build Coastguard Worker			base[c] = V[a].const
971*387f9dfdSAndroid Build Coastguard Worker		else
972*387f9dfdSAndroid Build Coastguard Worker			error('NYI: B[C] where B is not Lua table, BPF map, or pointer')
973*387f9dfdSAndroid Build Coastguard Worker		end
974*387f9dfdSAndroid Build Coastguard Worker	end,
975*387f9dfdSAndroid Build Coastguard Worker	TGETB = function (a, b, _, d) -- TGETB (A = B[D])
976*387f9dfdSAndroid Build Coastguard Worker		local base = V[b].const
977*387f9dfdSAndroid Build Coastguard Worker		assert(type(base) == 'table', 'NYI: B[C] where C is string and B not Lua table or BPF map')
978*387f9dfdSAndroid Build Coastguard Worker		if a ~= b then vset(a) end
979*387f9dfdSAndroid Build Coastguard Worker		if base.__map then -- BPF map read (constant)
980*387f9dfdSAndroid Build Coastguard Worker			MAP_GET(a, b, nil, d)
981*387f9dfdSAndroid Build Coastguard Worker		-- Pointer access with a dissector (traditional uses BPF_LD, direct uses BPF_MEM)
982*387f9dfdSAndroid Build Coastguard Worker		elseif V[b].source and V[b].source:find('ptr_to_') then
983*387f9dfdSAndroid Build Coastguard Worker			local vtype = base.__dissector and base.__dissector or ffi.typeof('uint8_t')
984*387f9dfdSAndroid Build Coastguard Worker			LOAD(a, b, d, vtype)
985*387f9dfdSAndroid Build Coastguard Worker		-- Specialise PTR[0] as dereference operator
986*387f9dfdSAndroid Build Coastguard Worker		elseif cdef.isptr(V[b].type) and d == 0 then
987*387f9dfdSAndroid Build Coastguard Worker			vcopy(a, b)
988*387f9dfdSAndroid Build Coastguard Worker			local dst_reg = vreg(a)
989*387f9dfdSAndroid Build Coastguard Worker			vderef(dst_reg, dst_reg, V[a])
990*387f9dfdSAndroid Build Coastguard Worker			V[a].type = V[a].const.__dissector
991*387f9dfdSAndroid Build Coastguard Worker		else
992*387f9dfdSAndroid Build Coastguard Worker			error('NYI: A = B[D], where B is not Lua table or packet dissector or pointer dereference')
993*387f9dfdSAndroid Build Coastguard Worker		end
994*387f9dfdSAndroid Build Coastguard Worker	end,
995*387f9dfdSAndroid Build Coastguard Worker	TGETV = function (a, b, _, d) -- TGETV (A = B[D])
996*387f9dfdSAndroid Build Coastguard Worker		local base = V[b].const
997*387f9dfdSAndroid Build Coastguard Worker		assert(type(base) == 'table', 'NYI: B[C] where C is string and B not Lua table or BPF map')
998*387f9dfdSAndroid Build Coastguard Worker		if a ~= b then vset(a) end
999*387f9dfdSAndroid Build Coastguard Worker		if base.__map then -- BPF map read
1000*387f9dfdSAndroid Build Coastguard Worker			MAP_GET(a, b, d)
1001*387f9dfdSAndroid Build Coastguard Worker		-- Pointer access with a dissector (traditional uses BPF_LD, direct uses BPF_MEM)
1002*387f9dfdSAndroid Build Coastguard Worker		elseif V[b].source and V[b].source:find('ptr_to_') then
1003*387f9dfdSAndroid Build Coastguard Worker			local vtype = base.__dissector and base.__dissector or ffi.typeof('uint8_t')
1004*387f9dfdSAndroid Build Coastguard Worker			LOAD(a, b, d, vtype)
1005*387f9dfdSAndroid Build Coastguard Worker		-- Constant dereference
1006*387f9dfdSAndroid Build Coastguard Worker		elseif type(V[d].const) == 'number' then
1007*387f9dfdSAndroid Build Coastguard Worker			V[a].const = base[V[d].const]
1008*387f9dfdSAndroid Build Coastguard Worker		else
1009*387f9dfdSAndroid Build Coastguard Worker			error('NYI: A = B[D], where B is not Lua table or packet dissector or pointer dereference')
1010*387f9dfdSAndroid Build Coastguard Worker		end
1011*387f9dfdSAndroid Build Coastguard Worker	end,
1012*387f9dfdSAndroid Build Coastguard Worker	TGETS = function (a, b, c, _) -- TGETS (A = B[C])
1013*387f9dfdSAndroid Build Coastguard Worker		local base = V[b].const
1014*387f9dfdSAndroid Build Coastguard Worker		assert(type(base) == 'table', 'NYI: B[C] where C is string and B not Lua table or BPF map')
1015*387f9dfdSAndroid Build Coastguard Worker		if a ~= b then vset(a) end
1016*387f9dfdSAndroid Build Coastguard Worker		if base.__dissector then
1017*387f9dfdSAndroid Build Coastguard Worker			local ofs,bpos,bsize = ffi.offsetof(base.__dissector, c)
1018*387f9dfdSAndroid Build Coastguard Worker			-- Resolve table key using metatable
1019*387f9dfdSAndroid Build Coastguard Worker			if not ofs and type(base.__dissector[c]) == 'string' then
1020*387f9dfdSAndroid Build Coastguard Worker				c = base.__dissector[c]
1021*387f9dfdSAndroid Build Coastguard Worker				ofs,bpos,bsize = ffi.offsetof(base.__dissector, c)
1022*387f9dfdSAndroid Build Coastguard Worker			end
1023*387f9dfdSAndroid Build Coastguard Worker			if not ofs and proto[c] then -- Load new dissector on given offset
1024*387f9dfdSAndroid Build Coastguard Worker				BUILTIN(proto[c], a, b, c)
1025*387f9dfdSAndroid Build Coastguard Worker			else
1026*387f9dfdSAndroid Build Coastguard Worker				-- Loading register from offset is a little bit tricky as there are
1027*387f9dfdSAndroid Build Coastguard Worker				-- several data sources and value loading modes with different restrictions
1028*387f9dfdSAndroid Build Coastguard Worker				-- such as checking pointer values for NULL compared to using stack.
1029*387f9dfdSAndroid Build Coastguard Worker				assert(ofs, tostring(base.__dissector)..'.'..c..' attribute not exists')
1030*387f9dfdSAndroid Build Coastguard Worker				if a ~= b then vset(a) end
1031*387f9dfdSAndroid Build Coastguard Worker				-- Dissected value is probably not constant anymore
1032*387f9dfdSAndroid Build Coastguard Worker				local new_const = nil
1033*387f9dfdSAndroid Build Coastguard Worker				local w, atype = builtins.sizeofattr(base.__dissector, c)
1034*387f9dfdSAndroid Build Coastguard Worker				-- [SP+K] addressing using R10 (stack pointer)
1035*387f9dfdSAndroid Build Coastguard Worker				-- Doesn't need to be checked for NULL
1036*387f9dfdSAndroid Build Coastguard Worker				if base.__base and base.__base > 0 then
1037*387f9dfdSAndroid Build Coastguard Worker					if cdef.isptr(atype) then -- If the member is pointer type, update base pointer with offset
1038*387f9dfdSAndroid Build Coastguard Worker						new_const = {__base = base.__base-ofs}
1039*387f9dfdSAndroid Build Coastguard Worker					else
1040*387f9dfdSAndroid Build Coastguard Worker						local dst_reg = vreg(a, nil, true)
1041*387f9dfdSAndroid Build Coastguard Worker						emit(BPF.MEM + BPF.LDX + const_width[w], dst_reg, 10, -base.__base+ofs, 0)
1042*387f9dfdSAndroid Build Coastguard Worker					end
1043*387f9dfdSAndroid Build Coastguard Worker				-- Pointer access with a dissector (traditional uses BPF_LD, direct uses BPF_MEM)
1044*387f9dfdSAndroid Build Coastguard Worker				elseif V[b].source and V[b].source:find('ptr_to_') then
1045*387f9dfdSAndroid Build Coastguard Worker					LOAD(a, b, ofs, atype)
1046*387f9dfdSAndroid Build Coastguard Worker				else
1047*387f9dfdSAndroid Build Coastguard Worker					error('NYI: B[C] where B is not Lua table, BPF map, or pointer')
1048*387f9dfdSAndroid Build Coastguard Worker				end
1049*387f9dfdSAndroid Build Coastguard Worker				-- Bitfield, must be further narrowed with a bitmask/shift
1050*387f9dfdSAndroid Build Coastguard Worker				if bpos then
1051*387f9dfdSAndroid Build Coastguard Worker					local mask = 0
1052*387f9dfdSAndroid Build Coastguard Worker					for i=bpos+1,bpos+bsize do
1053*387f9dfdSAndroid Build Coastguard Worker						mask = bit.bor(mask, bit.lshift(1, w*8-i))
1054*387f9dfdSAndroid Build Coastguard Worker					end
1055*387f9dfdSAndroid Build Coastguard Worker					emit(BPF.ALU64 + BPF.AND + BPF.K, vreg(a), 0, 0, mask)
1056*387f9dfdSAndroid Build Coastguard Worker					-- Free optimization: single-bit values need just boolean result
1057*387f9dfdSAndroid Build Coastguard Worker					if bsize > 1 then
1058*387f9dfdSAndroid Build Coastguard Worker						local shift = w*8-bsize-bpos
1059*387f9dfdSAndroid Build Coastguard Worker						if shift > 0 then
1060*387f9dfdSAndroid Build Coastguard Worker							emit(BPF.ALU64 + BPF.RSH + BPF.K, vreg(a), 0, 0, shift)
1061*387f9dfdSAndroid Build Coastguard Worker						end
1062*387f9dfdSAndroid Build Coastguard Worker					end
1063*387f9dfdSAndroid Build Coastguard Worker				end
1064*387f9dfdSAndroid Build Coastguard Worker				V[a].type = atype
1065*387f9dfdSAndroid Build Coastguard Worker				V[a].const = new_const
1066*387f9dfdSAndroid Build Coastguard Worker				V[a].source = V[b].source
1067*387f9dfdSAndroid Build Coastguard Worker				-- Track direct access to skb data
1068*387f9dfdSAndroid Build Coastguard Worker				-- see https://www.kernel.org/doc/Documentation/networking/filter.txt "Direct packet access"
1069*387f9dfdSAndroid Build Coastguard Worker				if ffi.istype(base.__dissector, ffi.typeof('struct sk_buff')) then
1070*387f9dfdSAndroid Build Coastguard Worker					-- Direct access to skb uses skb->data and skb->data_end
1071*387f9dfdSAndroid Build Coastguard Worker					-- which are encoded as u32, but are actually pointers
1072*387f9dfdSAndroid Build Coastguard Worker					if c == 'data' or c == 'data_end' then
1073*387f9dfdSAndroid Build Coastguard Worker						V[a].const = {__dissector = ffi.typeof('uint8_t')}
1074*387f9dfdSAndroid Build Coastguard Worker						V[a].source = 'ptr_to_skb'
1075*387f9dfdSAndroid Build Coastguard Worker					end
1076*387f9dfdSAndroid Build Coastguard Worker				end
1077*387f9dfdSAndroid Build Coastguard Worker			end
1078*387f9dfdSAndroid Build Coastguard Worker		else
1079*387f9dfdSAndroid Build Coastguard Worker			V[a].const = base[c]
1080*387f9dfdSAndroid Build Coastguard Worker		end
1081*387f9dfdSAndroid Build Coastguard Worker	end,
1082*387f9dfdSAndroid Build Coastguard Worker	-- Loops and branches
1083*387f9dfdSAndroid Build Coastguard Worker	CALLM = function (a, b, _, d) -- A = A(A+1, ..., A+D+MULTRES)
1084*387f9dfdSAndroid Build Coastguard Worker		-- NYI: Support single result only
1085*387f9dfdSAndroid Build Coastguard Worker		CALL(a, b, d+2)
1086*387f9dfdSAndroid Build Coastguard Worker	end,
1087*387f9dfdSAndroid Build Coastguard Worker	CALL = function (a, b, _, d) -- A = A(A+1, ..., A+D-1)
1088*387f9dfdSAndroid Build Coastguard Worker		CALL(a, b, d)
1089*387f9dfdSAndroid Build Coastguard Worker	end,
1090*387f9dfdSAndroid Build Coastguard Worker	JMP = function (a, _, c, _) -- JMP
1091*387f9dfdSAndroid Build Coastguard Worker		-- Discard unused slots after jump
1092*387f9dfdSAndroid Build Coastguard Worker		for i, _ in pairs(V) do
1093*387f9dfdSAndroid Build Coastguard Worker			if i >= a and i < stackslots then
1094*387f9dfdSAndroid Build Coastguard Worker				V[i] = nil
1095*387f9dfdSAndroid Build Coastguard Worker			end
1096*387f9dfdSAndroid Build Coastguard Worker		end
1097*387f9dfdSAndroid Build Coastguard Worker		-- Cross basic block boundary if the jump target isn't provably unreachable
1098*387f9dfdSAndroid Build Coastguard Worker		local val = code.fixup[c] or {}
1099*387f9dfdSAndroid Build Coastguard Worker		if code.seen_cmp and code.seen_cmp ~= ALWAYS then
1100*387f9dfdSAndroid Build Coastguard Worker			if code.seen_cmp ~= NEVER then -- Do not emit the jump or fixup
1101*387f9dfdSAndroid Build Coastguard Worker				-- Store previous CMP insn for reemitting after compensation code
1102*387f9dfdSAndroid Build Coastguard Worker				local jmpi = ffi.new('struct bpf_insn', code.insn[code.pc-1])
1103*387f9dfdSAndroid Build Coastguard Worker				code.pc = code.pc - 1
1104*387f9dfdSAndroid Build Coastguard Worker				-- First branch point, emit compensation code
1105*387f9dfdSAndroid Build Coastguard Worker				local Vcomp = Vstate[c]
1106*387f9dfdSAndroid Build Coastguard Worker				if not Vcomp then
1107*387f9dfdSAndroid Build Coastguard Worker					-- Select scratch register (R0-5) that isn't used as operand
1108*387f9dfdSAndroid Build Coastguard Worker					-- in the CMP instruction, as the variable may not be live, after
1109*387f9dfdSAndroid Build Coastguard Worker					-- the JMP, but it may be used in the JMP+CMP instruction itself
1110*387f9dfdSAndroid Build Coastguard Worker					local tmp_reg = 0
1111*387f9dfdSAndroid Build Coastguard Worker					for reg = 0, 5 do
1112*387f9dfdSAndroid Build Coastguard Worker						if reg ~= jmpi.dst_reg and reg ~= jmpi.src_reg then
1113*387f9dfdSAndroid Build Coastguard Worker							tmp_reg = reg
1114*387f9dfdSAndroid Build Coastguard Worker							break
1115*387f9dfdSAndroid Build Coastguard Worker						end
1116*387f9dfdSAndroid Build Coastguard Worker					end
1117*387f9dfdSAndroid Build Coastguard Worker					-- Force materialization of constants at the end of BB
1118*387f9dfdSAndroid Build Coastguard Worker					for i, v in pairs(V) do
1119*387f9dfdSAndroid Build Coastguard Worker						if not v.reg and cdef.isimmconst(v) then
1120*387f9dfdSAndroid Build Coastguard Worker							vreg(i, tmp_reg) -- Load to TMP register (not saved)
1121*387f9dfdSAndroid Build Coastguard Worker							reg_spill(i) -- Spill caller-saved registers
1122*387f9dfdSAndroid Build Coastguard Worker						end
1123*387f9dfdSAndroid Build Coastguard Worker					end
1124*387f9dfdSAndroid Build Coastguard Worker					-- Record variable state
1125*387f9dfdSAndroid Build Coastguard Worker					Vstate[c] = V
1126*387f9dfdSAndroid Build Coastguard Worker					Vcomp = V
1127*387f9dfdSAndroid Build Coastguard Worker					V = table_copy(V)
1128*387f9dfdSAndroid Build Coastguard Worker				-- Variable state already set, emit specific compensation code
1129*387f9dfdSAndroid Build Coastguard Worker				else
1130*387f9dfdSAndroid Build Coastguard Worker					bb_end(Vcomp)
1131*387f9dfdSAndroid Build Coastguard Worker				end
1132*387f9dfdSAndroid Build Coastguard Worker				-- Record pointer NULL check from condition
1133*387f9dfdSAndroid Build Coastguard Worker				-- If the condition checks pointer variable against NULL,
1134*387f9dfdSAndroid Build Coastguard Worker				-- we can assume it will not be NULL in the fall-through block
1135*387f9dfdSAndroid Build Coastguard Worker				if code.seen_null_guard then
1136*387f9dfdSAndroid Build Coastguard Worker					local var = code.seen_null_guard
1137*387f9dfdSAndroid Build Coastguard Worker					-- The null guard can have two forms:
1138*387f9dfdSAndroid Build Coastguard Worker					--   if x == nil then goto
1139*387f9dfdSAndroid Build Coastguard Worker					--   if x ~= nil then goto
1140*387f9dfdSAndroid Build Coastguard Worker					-- First form guarantees that the variable will be non-nil on the following instruction
1141*387f9dfdSAndroid Build Coastguard Worker					-- Second form guarantees that the variable will be non-nil at the jump target
1142*387f9dfdSAndroid Build Coastguard Worker					local vinfo = code.seen_null_guard_inverse and Vcomp[var] or V[var]
1143*387f9dfdSAndroid Build Coastguard Worker					if vinfo.source then
1144*387f9dfdSAndroid Build Coastguard Worker						local pos = vinfo.source:find('_or_null', 1, true)
1145*387f9dfdSAndroid Build Coastguard Worker						if pos then
1146*387f9dfdSAndroid Build Coastguard Worker							vinfo.source = vinfo.source:sub(1, pos - 1)
1147*387f9dfdSAndroid Build Coastguard Worker						end
1148*387f9dfdSAndroid Build Coastguard Worker					end
1149*387f9dfdSAndroid Build Coastguard Worker				end
1150*387f9dfdSAndroid Build Coastguard Worker				-- Reemit CMP insn
1151*387f9dfdSAndroid Build Coastguard Worker				emit(jmpi.code, jmpi.dst_reg, jmpi.src_reg, jmpi.off, jmpi.imm)
1152*387f9dfdSAndroid Build Coastguard Worker				-- Fuse JMP into previous CMP opcode, mark JMP target for fixup
1153*387f9dfdSAndroid Build Coastguard Worker				-- as we don't knot the relative offset in generated code yet
1154*387f9dfdSAndroid Build Coastguard Worker				table.insert(val, code.pc-1)
1155*387f9dfdSAndroid Build Coastguard Worker				code.fixup[c] = val
1156*387f9dfdSAndroid Build Coastguard Worker			end
1157*387f9dfdSAndroid Build Coastguard Worker			code.seen_cmp = nil
1158*387f9dfdSAndroid Build Coastguard Worker			code.seen_null_guard = nil
1159*387f9dfdSAndroid Build Coastguard Worker			code.seen_null_guard_inverse = nil
1160*387f9dfdSAndroid Build Coastguard Worker		elseif c == code.bc_pc + 1 then -- luacheck: ignore 542
1161*387f9dfdSAndroid Build Coastguard Worker			-- Eliminate jumps to next immediate instruction
1162*387f9dfdSAndroid Build Coastguard Worker			-- e.g. 0002    JMP      1 => 0003
1163*387f9dfdSAndroid Build Coastguard Worker		else
1164*387f9dfdSAndroid Build Coastguard Worker			-- We need to synthesise a condition that's always true, however
1165*387f9dfdSAndroid Build Coastguard Worker			-- BPF prohibits pointer arithmetic to prevent pointer leaks
1166*387f9dfdSAndroid Build Coastguard Worker			-- so we have to clear out one register and use it for cmp that's always true
1167*387f9dfdSAndroid Build Coastguard Worker			local dst_reg = reg_alloc(stackslots)
1168*387f9dfdSAndroid Build Coastguard Worker			V[stackslots].reg = nil -- Only temporary allocation
1169*387f9dfdSAndroid Build Coastguard Worker			-- First branch point, emit compensation code
1170*387f9dfdSAndroid Build Coastguard Worker			local Vcomp = Vstate[c]
1171*387f9dfdSAndroid Build Coastguard Worker			if not Vcomp then
1172*387f9dfdSAndroid Build Coastguard Worker				-- Force materialization of constants at the end of BB
1173*387f9dfdSAndroid Build Coastguard Worker				for i, v in pairs(V) do
1174*387f9dfdSAndroid Build Coastguard Worker					if not v.reg and cdef.isimmconst(v) then
1175*387f9dfdSAndroid Build Coastguard Worker						vreg(i, dst_reg) -- Load to TMP register (not saved)
1176*387f9dfdSAndroid Build Coastguard Worker						reg_spill(i) -- Spill caller-saved registers
1177*387f9dfdSAndroid Build Coastguard Worker					end
1178*387f9dfdSAndroid Build Coastguard Worker				end
1179*387f9dfdSAndroid Build Coastguard Worker				-- Record variable state
1180*387f9dfdSAndroid Build Coastguard Worker				Vstate[c] = V
1181*387f9dfdSAndroid Build Coastguard Worker				V = table_copy(V)
1182*387f9dfdSAndroid Build Coastguard Worker			-- Variable state already set, emit specific compensation code
1183*387f9dfdSAndroid Build Coastguard Worker			else
1184*387f9dfdSAndroid Build Coastguard Worker				bb_end(Vcomp)
1185*387f9dfdSAndroid Build Coastguard Worker			end
1186*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.ALU64 + BPF.MOV + BPF.K, dst_reg, 0, 0, 0)
1187*387f9dfdSAndroid Build Coastguard Worker			emit(BPF.JMP + BPF.JEQ + BPF.K, dst_reg, 0, 0xffff, 0)
1188*387f9dfdSAndroid Build Coastguard Worker			table.insert(val, code.pc-1) -- Fixup JMP target
1189*387f9dfdSAndroid Build Coastguard Worker			code.reachable = false -- Code following the JMP is not reachable
1190*387f9dfdSAndroid Build Coastguard Worker			code.fixup[c] = val
1191*387f9dfdSAndroid Build Coastguard Worker		end
1192*387f9dfdSAndroid Build Coastguard Worker	end,
1193*387f9dfdSAndroid Build Coastguard Worker	RET1 = function (a, _, _, _) -- RET1
1194*387f9dfdSAndroid Build Coastguard Worker		-- Free optimisation: spilled variable will not be filled again
1195*387f9dfdSAndroid Build Coastguard Worker		for i, v in pairs(V) do
1196*387f9dfdSAndroid Build Coastguard Worker			if i ~= a then v.reg = nil end
1197*387f9dfdSAndroid Build Coastguard Worker		end
1198*387f9dfdSAndroid Build Coastguard Worker		if V[a].reg ~= 0 then vreg(a, 0) end
1199*387f9dfdSAndroid Build Coastguard Worker		-- Convenience: dereference pointer variables
1200*387f9dfdSAndroid Build Coastguard Worker		-- e.g. 'return map[k]' will return actual map value, not pointer
1201*387f9dfdSAndroid Build Coastguard Worker		if cdef.isptr(V[a].type) then
1202*387f9dfdSAndroid Build Coastguard Worker			vderef(0, 0, V[a])
1203*387f9dfdSAndroid Build Coastguard Worker		end
1204*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.JMP + BPF.EXIT, 0, 0, 0, 0)
1205*387f9dfdSAndroid Build Coastguard Worker		code.reachable = false
1206*387f9dfdSAndroid Build Coastguard Worker	end,
1207*387f9dfdSAndroid Build Coastguard Worker	RET0 = function (_, _, _, _) -- RET0
1208*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.ALU64 + BPF.MOV + BPF.K, 0, 0, 0, 0)
1209*387f9dfdSAndroid Build Coastguard Worker		emit(BPF.JMP + BPF.EXIT, 0, 0, 0, 0)
1210*387f9dfdSAndroid Build Coastguard Worker		code.reachable = false
1211*387f9dfdSAndroid Build Coastguard Worker	end,
1212*387f9dfdSAndroid Build Coastguard Worker	compile = function ()
1213*387f9dfdSAndroid Build Coastguard Worker		return code
1214*387f9dfdSAndroid Build Coastguard Worker	end
1215*387f9dfdSAndroid Build Coastguard Worker}
1216*387f9dfdSAndroid Build Coastguard Worker
1217*387f9dfdSAndroid Build Coastguard Worker-- Composite instructions
1218*387f9dfdSAndroid Build Coastguard Workerfunction BC.CALLT(a, _, _, d) -- Tailcall: return A(A+1, ..., A+D-1)
1219*387f9dfdSAndroid Build Coastguard Worker	CALL(a, 1, d)
1220*387f9dfdSAndroid Build Coastguard Worker	BC.RET1(a)
1221*387f9dfdSAndroid Build Coastguard Workerend
1222*387f9dfdSAndroid Build Coastguard Worker
1223*387f9dfdSAndroid Build Coastguard Worker-- Always initialize R6 with R1 context
1224*387f9dfdSAndroid Build Coastguard Workeremit(BPF.ALU64 + BPF.MOV + BPF.X, 6, 1, 0, 0)
1225*387f9dfdSAndroid Build Coastguard Worker-- Register R6 as context variable (first argument)
1226*387f9dfdSAndroid Build Coastguard Workerif params and params > 0 then
1227*387f9dfdSAndroid Build Coastguard Worker	vset(0, 6, param_types[1] or proto.skb)
1228*387f9dfdSAndroid Build Coastguard Worker	assert(V[0].source == V[0].const.source) -- Propagate source annotation from typeinfo
1229*387f9dfdSAndroid Build Coastguard Workerend
1230*387f9dfdSAndroid Build Coastguard Worker-- Register tmpvars
1231*387f9dfdSAndroid Build Coastguard Workervset(stackslots)
1232*387f9dfdSAndroid Build Coastguard Workervset(stackslots+1)
1233*387f9dfdSAndroid Build Coastguard Workerreturn setmetatable(BC, {
1234*387f9dfdSAndroid Build Coastguard Worker	__index = function (_, k, _)
1235*387f9dfdSAndroid Build Coastguard Worker		if type(k) == 'number' then
1236*387f9dfdSAndroid Build Coastguard Worker			local op_str = string.sub(require('jit.vmdef').bcnames, 6*k+1, 6*k+6)
1237*387f9dfdSAndroid Build Coastguard Worker			error(string.format("NYI: opcode '0x%02x' (%-04s)", k, op_str))
1238*387f9dfdSAndroid Build Coastguard Worker		end
1239*387f9dfdSAndroid Build Coastguard Worker	end,
1240*387f9dfdSAndroid Build Coastguard Worker	__call = function (t, op, a, b, c, d)
1241*387f9dfdSAndroid Build Coastguard Worker		code.bc_pc = code.bc_pc + 1
1242*387f9dfdSAndroid Build Coastguard Worker		-- Exitting BB straight through, emit compensation code
1243*387f9dfdSAndroid Build Coastguard Worker		if Vstate[code.bc_pc] then
1244*387f9dfdSAndroid Build Coastguard Worker			if code.reachable then
1245*387f9dfdSAndroid Build Coastguard Worker				-- Instruction is reachable from previous line
1246*387f9dfdSAndroid Build Coastguard Worker				-- so we must make the variable allocation consistent
1247*387f9dfdSAndroid Build Coastguard Worker				-- with the variable allocation at the jump source
1248*387f9dfdSAndroid Build Coastguard Worker				-- e.g. 0001 x:R0 = 5
1249*387f9dfdSAndroid Build Coastguard Worker				--      0002 if rand() then goto 0005
1250*387f9dfdSAndroid Build Coastguard Worker				--      0003 x:R0 -> x:stack
1251*387f9dfdSAndroid Build Coastguard Worker				--      0004 y:R0 = 5
1252*387f9dfdSAndroid Build Coastguard Worker				--      0005 x:? = 10 <-- x was in R0 before jump, and stack after jump
1253*387f9dfdSAndroid Build Coastguard Worker				bb_end(Vstate[code.bc_pc])
1254*387f9dfdSAndroid Build Coastguard Worker			else
1255*387f9dfdSAndroid Build Coastguard Worker				-- Instruction isn't reachable from previous line, restore variable layout
1256*387f9dfdSAndroid Build Coastguard Worker				-- e.g. RET or condition-less JMP on previous line
1257*387f9dfdSAndroid Build Coastguard Worker				V = table_copy(Vstate[code.bc_pc])
1258*387f9dfdSAndroid Build Coastguard Worker			end
1259*387f9dfdSAndroid Build Coastguard Worker		end
1260*387f9dfdSAndroid Build Coastguard Worker		-- Perform fixup of jump targets
1261*387f9dfdSAndroid Build Coastguard Worker		-- We need to do this because the number of consumed and emitted
1262*387f9dfdSAndroid Build Coastguard Worker		-- bytecode instructions is different
1263*387f9dfdSAndroid Build Coastguard Worker		local fixup = code.fixup[code.bc_pc]
1264*387f9dfdSAndroid Build Coastguard Worker		if fixup ~= nil then
1265*387f9dfdSAndroid Build Coastguard Worker			-- Patch JMP source insn with relative offset
1266*387f9dfdSAndroid Build Coastguard Worker			for _,pc in ipairs(fixup) do
1267*387f9dfdSAndroid Build Coastguard Worker				code.insn[pc].off = code.pc - 1 - pc
1268*387f9dfdSAndroid Build Coastguard Worker			end
1269*387f9dfdSAndroid Build Coastguard Worker			code.fixup[code.bc_pc] = nil
1270*387f9dfdSAndroid Build Coastguard Worker			code.reachable = true
1271*387f9dfdSAndroid Build Coastguard Worker		end
1272*387f9dfdSAndroid Build Coastguard Worker		-- Execute
1273*387f9dfdSAndroid Build Coastguard Worker		if code.reachable then
1274*387f9dfdSAndroid Build Coastguard Worker			assert(t[op], string.format('NYI: instruction %s, parameters: %s,%s,%s,%s', op,a,b,c,d))
1275*387f9dfdSAndroid Build Coastguard Worker			return t[op](a, b, c, d)
1276*387f9dfdSAndroid Build Coastguard Worker		end
1277*387f9dfdSAndroid Build Coastguard Worker	end,
1278*387f9dfdSAndroid Build Coastguard Worker})
1279*387f9dfdSAndroid Build Coastguard Workerend
1280*387f9dfdSAndroid Build Coastguard Worker
1281*387f9dfdSAndroid Build Coastguard Worker-- Emitted code dump
1282*387f9dfdSAndroid Build Coastguard Workerlocal function dump_mem(cls, ins, _, fuse)
1283*387f9dfdSAndroid Build Coastguard Worker	-- This is a very dense MEM instruction decoder without much explanation
1284*387f9dfdSAndroid Build Coastguard Worker	-- Refer to https://www.kernel.org/doc/Documentation/networking/filter.txt for instruction format
1285*387f9dfdSAndroid Build Coastguard Worker	local mode = bit.band(ins.code, 0xe0)
1286*387f9dfdSAndroid Build Coastguard Worker	if mode == BPF.XADD then cls = 5 end -- The only mode
1287*387f9dfdSAndroid Build Coastguard Worker	local op_1 = {'LD', 'LDX', 'ST', 'STX', '', 'XADD'}
1288*387f9dfdSAndroid Build Coastguard Worker	local op_2 = {[0]='W', [8]='H', [16]='B', [24]='DW'}
1289*387f9dfdSAndroid Build Coastguard Worker	local name = op_1[cls+1] .. op_2[bit.band(ins.code, 0x18)]
1290*387f9dfdSAndroid Build Coastguard Worker	local off = tonumber(ffi.cast('int16_t', ins.off)) -- Reinterpret as signed
1291*387f9dfdSAndroid Build Coastguard Worker	local dst = cls < 2 and 'R'..ins.dst_reg or string.format('[R%d%+d]', ins.dst_reg, off)
1292*387f9dfdSAndroid Build Coastguard Worker	local src = cls % 2 == 0 and '#'..ins.imm or 'R'..ins.src_reg
1293*387f9dfdSAndroid Build Coastguard Worker	if cls == BPF.LDX then src = string.format('[R%d%+d]', ins.src_reg, off) end
1294*387f9dfdSAndroid Build Coastguard Worker	if mode == BPF.ABS then src = string.format('skb[%d]', ins.imm) end
1295*387f9dfdSAndroid Build Coastguard Worker	if mode == BPF.IND then src = string.format('skb[R%d%+d]', ins.src_reg, ins.imm) end
1296*387f9dfdSAndroid Build Coastguard Worker	return string.format('%s\t%s\t%s', fuse and '' or name, fuse and '' or dst, src)
1297*387f9dfdSAndroid Build Coastguard Workerend
1298*387f9dfdSAndroid Build Coastguard Worker
1299*387f9dfdSAndroid Build Coastguard Workerlocal function dump_alu(cls, ins, pc)
1300*387f9dfdSAndroid Build Coastguard Worker	local alu = {'ADD', 'SUB', 'MUL', 'DIV', 'OR', 'AND', 'LSH', 'RSH', 'NEG', 'MOD', 'XOR', 'MOV', 'ARSH', 'END' }
1301*387f9dfdSAndroid Build Coastguard Worker	local jmp = {'JA', 'JEQ', 'JGT', 'JGE', 'JSET', 'JNE', 'JSGT', 'JSGE', 'CALL', 'EXIT'}
1302*387f9dfdSAndroid Build Coastguard Worker	local helper = {'unspec', 'map_lookup_elem', 'map_update_elem', 'map_delete_elem', 'probe_read', 'ktime_get_ns',
1303*387f9dfdSAndroid Build Coastguard Worker					'trace_printk', 'get_prandom_u32', 'get_smp_processor_id', 'skb_store_bytes',
1304*387f9dfdSAndroid Build Coastguard Worker					'l3_csum_replace', 'l4_csum_replace', 'tail_call', 'clone_redirect', 'get_current_pid_tgid',
1305*387f9dfdSAndroid Build Coastguard Worker					'get_current_uid_gid', 'get_current_comm', 'get_cgroup_classid', 'skb_vlan_push', 'skb_vlan_pop',
1306*387f9dfdSAndroid Build Coastguard Worker					'skb_get_tunnel_key', 'skb_set_tunnel_key', 'perf_event_read', 'redirect', 'get_route_realm',
1307*387f9dfdSAndroid Build Coastguard Worker					'perf_event_output', 'skb_load_bytes'}
1308*387f9dfdSAndroid Build Coastguard Worker	local op = 0
1309*387f9dfdSAndroid Build Coastguard Worker	-- This is a very dense ALU instruction decoder without much explanation
1310*387f9dfdSAndroid Build Coastguard Worker	-- Refer to https://www.kernel.org/doc/Documentation/networking/filter.txt for instruction format
1311*387f9dfdSAndroid Build Coastguard Worker	for i = 0,13 do if 0x10 * i == bit.band(ins.code, 0xf0) then op = i + 1 break end end
1312*387f9dfdSAndroid Build Coastguard Worker	local name = (cls == 5) and jmp[op] or alu[op]
1313*387f9dfdSAndroid Build Coastguard Worker	local src = (bit.band(ins.code, 0x08) == BPF.X) and 'R'..ins.src_reg or '#'..ins.imm
1314*387f9dfdSAndroid Build Coastguard Worker	local target = (cls == 5 and op < 9) and string.format('\t=> %04d', pc + ins.off + 1) or ''
1315*387f9dfdSAndroid Build Coastguard Worker	if cls == 5 and op == 9 then target = string.format('\t; %s', helper[ins.imm + 1] or tostring(ins.imm)) end
1316*387f9dfdSAndroid Build Coastguard Worker	return string.format('%s\t%s\t%s%s', name, 'R'..ins.dst_reg, src, target)
1317*387f9dfdSAndroid Build Coastguard Workerend
1318*387f9dfdSAndroid Build Coastguard Worker
1319*387f9dfdSAndroid Build Coastguard Workerlocal function dump_string(code, off, hide_counter)
1320*387f9dfdSAndroid Build Coastguard Worker	if not code then return end
1321*387f9dfdSAndroid Build Coastguard Worker	local cls_map = {
1322*387f9dfdSAndroid Build Coastguard Worker		[0] = dump_mem, [1] = dump_mem, [2] = dump_mem, [3] = dump_mem,
1323*387f9dfdSAndroid Build Coastguard Worker		[4] = dump_alu, [5] = dump_alu, [7] = dump_alu,
1324*387f9dfdSAndroid Build Coastguard Worker	}
1325*387f9dfdSAndroid Build Coastguard Worker	local result = {}
1326*387f9dfdSAndroid Build Coastguard Worker	local fused = false
1327*387f9dfdSAndroid Build Coastguard Worker	for i = off or 0, code.pc - 1 do
1328*387f9dfdSAndroid Build Coastguard Worker		local ins = code.insn[i]
1329*387f9dfdSAndroid Build Coastguard Worker		local cls = bit.band(ins.code, 0x07)
1330*387f9dfdSAndroid Build Coastguard Worker		local line = cls_map[cls](cls, ins, i, fused)
1331*387f9dfdSAndroid Build Coastguard Worker		if hide_counter then
1332*387f9dfdSAndroid Build Coastguard Worker			table.insert(result, line)
1333*387f9dfdSAndroid Build Coastguard Worker		else
1334*387f9dfdSAndroid Build Coastguard Worker			table.insert(result, string.format('%04u\t%s', i, line))
1335*387f9dfdSAndroid Build Coastguard Worker		end
1336*387f9dfdSAndroid Build Coastguard Worker		fused = string.find(line, 'LDDW', 1)
1337*387f9dfdSAndroid Build Coastguard Worker	end
1338*387f9dfdSAndroid Build Coastguard Worker	return table.concat(result, '\n')
1339*387f9dfdSAndroid Build Coastguard Workerend
1340*387f9dfdSAndroid Build Coastguard Worker
1341*387f9dfdSAndroid Build Coastguard Workerlocal function dump(code)
1342*387f9dfdSAndroid Build Coastguard Worker	if not code then return end
1343*387f9dfdSAndroid Build Coastguard Worker	print(string.format('-- BPF %s:0-%u', code.insn, code.pc))
1344*387f9dfdSAndroid Build Coastguard Worker	print(dump_string(code))
1345*387f9dfdSAndroid Build Coastguard Workerend
1346*387f9dfdSAndroid Build Coastguard Worker
1347*387f9dfdSAndroid Build Coastguard Workerlocal function compile(prog, params)
1348*387f9dfdSAndroid Build Coastguard Worker	-- Create code emitter sandbox, include caller locals
1349*387f9dfdSAndroid Build Coastguard Worker	local env = { pkt=proto.pkt, eth=proto.pkt, BPF=BPF, ffi=ffi }
1350*387f9dfdSAndroid Build Coastguard Worker	-- Include upvalues up to 4 nested scopes back
1351*387f9dfdSAndroid Build Coastguard Worker	-- the narrower scope overrides broader scope
1352*387f9dfdSAndroid Build Coastguard Worker	for k = 5, 2, -1 do
1353*387f9dfdSAndroid Build Coastguard Worker		local i = 1
1354*387f9dfdSAndroid Build Coastguard Worker		while true do
1355*387f9dfdSAndroid Build Coastguard Worker			local ok, n, v = pcall(debug.getlocal, k, i)
1356*387f9dfdSAndroid Build Coastguard Worker			if not ok or not n then break end
1357*387f9dfdSAndroid Build Coastguard Worker			env[n] = v
1358*387f9dfdSAndroid Build Coastguard Worker			i = i + 1
1359*387f9dfdSAndroid Build Coastguard Worker		end
1360*387f9dfdSAndroid Build Coastguard Worker	end
1361*387f9dfdSAndroid Build Coastguard Worker	setmetatable(env, {
1362*387f9dfdSAndroid Build Coastguard Worker		__index = function (_, k)
1363*387f9dfdSAndroid Build Coastguard Worker			return proto[k] or builtins[k] or _G[k]
1364*387f9dfdSAndroid Build Coastguard Worker		end
1365*387f9dfdSAndroid Build Coastguard Worker	})
1366*387f9dfdSAndroid Build Coastguard Worker	-- Create code emitter and compile LuaJIT bytecode
1367*387f9dfdSAndroid Build Coastguard Worker	if type(prog) == 'string' then prog = loadstring(prog) end
1368*387f9dfdSAndroid Build Coastguard Worker	-- Create error handler to print traceback
1369*387f9dfdSAndroid Build Coastguard Worker	local funci, pc = bytecode.funcinfo(prog), 0
1370*387f9dfdSAndroid Build Coastguard Worker	local E = create_emitter(env, funci.stackslots, funci.params, params or {})
1371*387f9dfdSAndroid Build Coastguard Worker	local on_err = function (e)
1372*387f9dfdSAndroid Build Coastguard Worker			funci = bytecode.funcinfo(prog, pc)
1373*387f9dfdSAndroid Build Coastguard Worker			local from, to = 0, 0
1374*387f9dfdSAndroid Build Coastguard Worker			for _ = 1, funci.currentline do
1375*387f9dfdSAndroid Build Coastguard Worker				from = to
1376*387f9dfdSAndroid Build Coastguard Worker				to = string.find(funci.source, '\n', from+1, true) or 0
1377*387f9dfdSAndroid Build Coastguard Worker			end
1378*387f9dfdSAndroid Build Coastguard Worker			print(funci.loc..':'..string.sub(funci.source, from+1, to-1))
1379*387f9dfdSAndroid Build Coastguard Worker			print('error: '..e)
1380*387f9dfdSAndroid Build Coastguard Worker			print(debug.traceback())
1381*387f9dfdSAndroid Build Coastguard Worker	end
1382*387f9dfdSAndroid Build Coastguard Worker	for _,op,a,b,c,d in bytecode.decoder(prog) do
1383*387f9dfdSAndroid Build Coastguard Worker		local ok, _, err = xpcall(E,on_err,op,a,b,c,d)
1384*387f9dfdSAndroid Build Coastguard Worker		if not ok then
1385*387f9dfdSAndroid Build Coastguard Worker			return nil, err
1386*387f9dfdSAndroid Build Coastguard Worker		end
1387*387f9dfdSAndroid Build Coastguard Worker	end
1388*387f9dfdSAndroid Build Coastguard Worker	return E:compile()
1389*387f9dfdSAndroid Build Coastguard Workerend
1390*387f9dfdSAndroid Build Coastguard Worker
1391*387f9dfdSAndroid Build Coastguard Worker-- BPF map interface
1392*387f9dfdSAndroid Build Coastguard Workerlocal bpf_map_mt = {
1393*387f9dfdSAndroid Build Coastguard Worker	__gc = function (map) S.close(map.fd) end,
1394*387f9dfdSAndroid Build Coastguard Worker	__len = function(map) return map.max_entries end,
1395*387f9dfdSAndroid Build Coastguard Worker	__index = function (map, k)
1396*387f9dfdSAndroid Build Coastguard Worker		if type(k) == 'string' then
1397*387f9dfdSAndroid Build Coastguard Worker			-- Return iterator
1398*387f9dfdSAndroid Build Coastguard Worker			if k == 'pairs' then
1399*387f9dfdSAndroid Build Coastguard Worker				return function(t, key)
1400*387f9dfdSAndroid Build Coastguard Worker					-- Get next key
1401*387f9dfdSAndroid Build Coastguard Worker					local next_key = ffi.new(ffi.typeof(t.key))
1402*387f9dfdSAndroid Build Coastguard Worker					local cur_key
1403*387f9dfdSAndroid Build Coastguard Worker					if key then
1404*387f9dfdSAndroid Build Coastguard Worker						cur_key = t.key
1405*387f9dfdSAndroid Build Coastguard Worker						t.key[0] = key
1406*387f9dfdSAndroid Build Coastguard Worker					else
1407*387f9dfdSAndroid Build Coastguard Worker						cur_key = ffi.new(ffi.typeof(t.key))
1408*387f9dfdSAndroid Build Coastguard Worker					end
1409*387f9dfdSAndroid Build Coastguard Worker					local ok, err = S.bpf_map_op(S.c.BPF_CMD.MAP_GET_NEXT_KEY, map.fd, cur_key, next_key)
1410*387f9dfdSAndroid Build Coastguard Worker					if not ok then return nil, err end
1411*387f9dfdSAndroid Build Coastguard Worker					-- Get next value
1412*387f9dfdSAndroid Build Coastguard Worker					assert(S.bpf_map_op(S.c.BPF_CMD.MAP_LOOKUP_ELEM, map.fd, next_key, map.val))
1413*387f9dfdSAndroid Build Coastguard Worker					return next_key[0], map.val[0]
1414*387f9dfdSAndroid Build Coastguard Worker				end, map, nil
1415*387f9dfdSAndroid Build Coastguard Worker			-- Read for perf event map
1416*387f9dfdSAndroid Build Coastguard Worker			elseif k == 'reader' then
1417*387f9dfdSAndroid Build Coastguard Worker				return function (pmap, pid, cpu, event_type)
1418*387f9dfdSAndroid Build Coastguard Worker					-- Caller must either specify PID or CPU
1419*387f9dfdSAndroid Build Coastguard Worker					if not pid or pid < 0 then
1420*387f9dfdSAndroid Build Coastguard Worker						assert((cpu and cpu >= 0), 'NYI: creating composed reader for all CPUs')
1421*387f9dfdSAndroid Build Coastguard Worker						pid = -1
1422*387f9dfdSAndroid Build Coastguard Worker					end
1423*387f9dfdSAndroid Build Coastguard Worker					-- Create BPF output reader
1424*387f9dfdSAndroid Build Coastguard Worker					local pe = S.t.perf_event_attr1()
1425*387f9dfdSAndroid Build Coastguard Worker					pe[0].type = 'software'
1426*387f9dfdSAndroid Build Coastguard Worker					pe[0].config = 'sw_bpf_output'
1427*387f9dfdSAndroid Build Coastguard Worker					pe[0].sample_type = 'raw'
1428*387f9dfdSAndroid Build Coastguard Worker					pe[0].sample_period = 1
1429*387f9dfdSAndroid Build Coastguard Worker					pe[0].wakeup_events = 1
1430*387f9dfdSAndroid Build Coastguard Worker					local reader, err = S.t.perf_reader(S.perf_event_open(pe, pid, cpu or -1))
1431*387f9dfdSAndroid Build Coastguard Worker					if not reader then return nil, tostring(err) end
1432*387f9dfdSAndroid Build Coastguard Worker					-- Register event reader fd in BPF map
1433*387f9dfdSAndroid Build Coastguard Worker					assert(cpu < pmap.max_entries, string.format('BPF map smaller than read CPU %d', cpu))
1434*387f9dfdSAndroid Build Coastguard Worker					pmap[cpu] = reader.fd
1435*387f9dfdSAndroid Build Coastguard Worker					-- Open memory map and start reading
1436*387f9dfdSAndroid Build Coastguard Worker					local ok, err = reader:start()
1437*387f9dfdSAndroid Build Coastguard Worker					assert(ok, tostring(err))
1438*387f9dfdSAndroid Build Coastguard Worker					ok, err = reader:mmap()
1439*387f9dfdSAndroid Build Coastguard Worker					assert(ok, tostring(err))
1440*387f9dfdSAndroid Build Coastguard Worker					return cdef.event_reader(reader, event_type)
1441*387f9dfdSAndroid Build Coastguard Worker				end
1442*387f9dfdSAndroid Build Coastguard Worker			-- Signalise this is a map type
1443*387f9dfdSAndroid Build Coastguard Worker			end
1444*387f9dfdSAndroid Build Coastguard Worker			return k == '__map'
1445*387f9dfdSAndroid Build Coastguard Worker		end
1446*387f9dfdSAndroid Build Coastguard Worker		-- Retrieve key
1447*387f9dfdSAndroid Build Coastguard Worker		map.key[0] = k
1448*387f9dfdSAndroid Build Coastguard Worker		local ok, err = S.bpf_map_op(S.c.BPF_CMD.MAP_LOOKUP_ELEM, map.fd, map.key, map.val)
1449*387f9dfdSAndroid Build Coastguard Worker		if not ok then return nil, err end
1450*387f9dfdSAndroid Build Coastguard Worker		return ffi.new(map.val_type, map.val[0])
1451*387f9dfdSAndroid Build Coastguard Worker	end,
1452*387f9dfdSAndroid Build Coastguard Worker	__newindex = function (map, k, v)
1453*387f9dfdSAndroid Build Coastguard Worker		map.key[0] = k
1454*387f9dfdSAndroid Build Coastguard Worker		if v == nil then
1455*387f9dfdSAndroid Build Coastguard Worker			return S.bpf_map_op(map.fd, S.c.BPF_CMD.MAP_DELETE_ELEM, map.key, nil)
1456*387f9dfdSAndroid Build Coastguard Worker		end
1457*387f9dfdSAndroid Build Coastguard Worker		map.val[0] = v
1458*387f9dfdSAndroid Build Coastguard Worker		return S.bpf_map_op(S.c.BPF_CMD.MAP_UPDATE_ELEM, map.fd, map.key, map.val)
1459*387f9dfdSAndroid Build Coastguard Worker	end,
1460*387f9dfdSAndroid Build Coastguard Worker}
1461*387f9dfdSAndroid Build Coastguard Worker
1462*387f9dfdSAndroid Build Coastguard Worker-- Linux tracing interface
1463*387f9dfdSAndroid Build Coastguard Workerlocal function trace_check_enabled(path)
1464*387f9dfdSAndroid Build Coastguard Worker	path = path or '/sys/kernel/debug/tracing'
1465*387f9dfdSAndroid Build Coastguard Worker	if S.statfs(path) then return true end
1466*387f9dfdSAndroid Build Coastguard Worker	return nil, 'debugfs not accessible: "mount -t debugfs nodev /sys/kernel/debug"? missing sudo?'
1467*387f9dfdSAndroid Build Coastguard Workerend
1468*387f9dfdSAndroid Build Coastguard Worker
1469*387f9dfdSAndroid Build Coastguard Worker-- Tracepoint interface
1470*387f9dfdSAndroid Build Coastguard Workerlocal tracepoint_mt = {
1471*387f9dfdSAndroid Build Coastguard Worker	__index = {
1472*387f9dfdSAndroid Build Coastguard Worker		bpf = function (t, prog)
1473*387f9dfdSAndroid Build Coastguard Worker			if type(prog) ~= 'table' then
1474*387f9dfdSAndroid Build Coastguard Worker				-- Create protocol parser with source probe
1475*387f9dfdSAndroid Build Coastguard Worker				prog = compile(prog, {proto.type(t.type, {source='ptr_to_probe'})})
1476*387f9dfdSAndroid Build Coastguard Worker			end
1477*387f9dfdSAndroid Build Coastguard Worker			-- Load the BPF program
1478*387f9dfdSAndroid Build Coastguard Worker			local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.TRACEPOINT, prog.insn, prog.pc)
1479*387f9dfdSAndroid Build Coastguard Worker			assert(prog_fd, tostring(err)..': '..tostring(log))
1480*387f9dfdSAndroid Build Coastguard Worker			-- Open tracepoint and attach
1481*387f9dfdSAndroid Build Coastguard Worker			t.reader:setbpf(prog_fd:getfd())
1482*387f9dfdSAndroid Build Coastguard Worker			table.insert(t.progs, prog_fd)
1483*387f9dfdSAndroid Build Coastguard Worker			return prog_fd
1484*387f9dfdSAndroid Build Coastguard Worker		end,
1485*387f9dfdSAndroid Build Coastguard Worker	}
1486*387f9dfdSAndroid Build Coastguard Worker}
1487*387f9dfdSAndroid Build Coastguard Worker-- Open tracepoint
1488*387f9dfdSAndroid Build Coastguard Workerlocal function tracepoint_open(path, pid, cpu, group_fd)
1489*387f9dfdSAndroid Build Coastguard Worker	-- Open tracepoint and compile tracepoint type
1490*387f9dfdSAndroid Build Coastguard Worker	local tp = assert(S.perf_tracepoint('/sys/kernel/debug/tracing/events/'..path))
1491*387f9dfdSAndroid Build Coastguard Worker	local tp_type = assert(cdef.tracepoint_type(path))
1492*387f9dfdSAndroid Build Coastguard Worker	-- Open tracepoint reader and create interface
1493*387f9dfdSAndroid Build Coastguard Worker	local reader = assert(S.perf_attach_tracepoint(tp, pid, cpu, group_fd))
1494*387f9dfdSAndroid Build Coastguard Worker	return setmetatable({tp=tp,type=tp_type,reader=reader,progs={}}, tracepoint_mt)
1495*387f9dfdSAndroid Build Coastguard Workerend
1496*387f9dfdSAndroid Build Coastguard Worker
1497*387f9dfdSAndroid Build Coastguard Workerlocal function trace_bpf(ptype, pname, pdef, retprobe, prog, pid, cpu, group_fd)
1498*387f9dfdSAndroid Build Coastguard Worker	-- Load BPF program
1499*387f9dfdSAndroid Build Coastguard Worker	if type(prog) ~= 'table' then
1500*387f9dfdSAndroid Build Coastguard Worker		prog = compile(prog, {proto.pt_regs})
1501*387f9dfdSAndroid Build Coastguard Worker	end
1502*387f9dfdSAndroid Build Coastguard Worker	local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.KPROBE, prog.insn, prog.pc)
1503*387f9dfdSAndroid Build Coastguard Worker	assert(prog_fd, tostring(err)..': '..tostring(log))
1504*387f9dfdSAndroid Build Coastguard Worker	-- Open tracepoint and attach
1505*387f9dfdSAndroid Build Coastguard Worker	local tp, err = S.perf_probe(ptype, pname, pdef, retprobe)
1506*387f9dfdSAndroid Build Coastguard Worker	if not tp then
1507*387f9dfdSAndroid Build Coastguard Worker		prog_fd:close()
1508*387f9dfdSAndroid Build Coastguard Worker		return nil, tostring(err)
1509*387f9dfdSAndroid Build Coastguard Worker	end
1510*387f9dfdSAndroid Build Coastguard Worker	local reader, err = S.perf_attach_tracepoint(tp, pid, cpu, group_fd, {sample_type='raw, callchain'})
1511*387f9dfdSAndroid Build Coastguard Worker	if not reader then
1512*387f9dfdSAndroid Build Coastguard Worker		prog_fd:close()
1513*387f9dfdSAndroid Build Coastguard Worker		S.perf_probe(ptype, pname, false)
1514*387f9dfdSAndroid Build Coastguard Worker		return nil, tostring(err)
1515*387f9dfdSAndroid Build Coastguard Worker	end
1516*387f9dfdSAndroid Build Coastguard Worker	local ok, err = reader:setbpf(prog_fd:getfd())
1517*387f9dfdSAndroid Build Coastguard Worker	if not ok then
1518*387f9dfdSAndroid Build Coastguard Worker		prog_fd:close()
1519*387f9dfdSAndroid Build Coastguard Worker		reader:close()
1520*387f9dfdSAndroid Build Coastguard Worker		S.perf_probe(ptype, pname, false)
1521*387f9dfdSAndroid Build Coastguard Worker		return nil, tostring(err)..' (kernel version should be at least 4.1)'
1522*387f9dfdSAndroid Build Coastguard Worker	end
1523*387f9dfdSAndroid Build Coastguard Worker	-- Create GC closure for reader to close BPF program
1524*387f9dfdSAndroid Build Coastguard Worker	-- and detach probe in correct order
1525*387f9dfdSAndroid Build Coastguard Worker	ffi.gc(reader, function ()
1526*387f9dfdSAndroid Build Coastguard Worker		prog_fd:close()
1527*387f9dfdSAndroid Build Coastguard Worker		reader:close()
1528*387f9dfdSAndroid Build Coastguard Worker		S.perf_probe(ptype, pname, false)
1529*387f9dfdSAndroid Build Coastguard Worker	end)
1530*387f9dfdSAndroid Build Coastguard Worker	return {reader=reader, prog=prog_fd, probe=pname, probe_type=ptype}
1531*387f9dfdSAndroid Build Coastguard Workerend
1532*387f9dfdSAndroid Build Coastguard Worker
1533*387f9dfdSAndroid Build Coastguard Worker-- Module interface
1534*387f9dfdSAndroid Build Coastguard Workerreturn setmetatable({
1535*387f9dfdSAndroid Build Coastguard Worker	new = create_emitter,
1536*387f9dfdSAndroid Build Coastguard Worker	dump = dump,
1537*387f9dfdSAndroid Build Coastguard Worker	dump_string = dump_string,
1538*387f9dfdSAndroid Build Coastguard Worker	maps = {},
1539*387f9dfdSAndroid Build Coastguard Worker	map = function (type, max_entries, key_ctype, val_ctype)
1540*387f9dfdSAndroid Build Coastguard Worker		if not key_ctype then key_ctype = ffi.typeof('uint32_t') end
1541*387f9dfdSAndroid Build Coastguard Worker		if not val_ctype then val_ctype = ffi.typeof('uint32_t') end
1542*387f9dfdSAndroid Build Coastguard Worker		if not max_entries then max_entries = 4096 end
1543*387f9dfdSAndroid Build Coastguard Worker		-- Special case for BPF_MAP_STACK_TRACE
1544*387f9dfdSAndroid Build Coastguard Worker		if S.c.BPF_MAP[type] == S.c.BPF_MAP.STACK_TRACE then
1545*387f9dfdSAndroid Build Coastguard Worker			key_ctype = ffi.typeof('int32_t')
1546*387f9dfdSAndroid Build Coastguard Worker			val_ctype = ffi.typeof('struct bpf_stacktrace')
1547*387f9dfdSAndroid Build Coastguard Worker		end
1548*387f9dfdSAndroid Build Coastguard Worker		local fd, err = S.bpf_map_create(S.c.BPF_MAP[type], ffi.sizeof(key_ctype), ffi.sizeof(val_ctype), max_entries)
1549*387f9dfdSAndroid Build Coastguard Worker		if not fd then return nil, tostring(err) end
1550*387f9dfdSAndroid Build Coastguard Worker		local map = setmetatable({
1551*387f9dfdSAndroid Build Coastguard Worker			max_entries = max_entries,
1552*387f9dfdSAndroid Build Coastguard Worker			key = ffi.new(ffi.typeof('$ [1]', key_ctype)),
1553*387f9dfdSAndroid Build Coastguard Worker			val = ffi.new(ffi.typeof('$ [1]', val_ctype)),
1554*387f9dfdSAndroid Build Coastguard Worker			map_type = S.c.BPF_MAP[type],
1555*387f9dfdSAndroid Build Coastguard Worker			key_type = key_ctype,
1556*387f9dfdSAndroid Build Coastguard Worker			val_type = val_ctype,
1557*387f9dfdSAndroid Build Coastguard Worker			fd = fd:nogc():getfd(),
1558*387f9dfdSAndroid Build Coastguard Worker		}, bpf_map_mt)
1559*387f9dfdSAndroid Build Coastguard Worker		return map
1560*387f9dfdSAndroid Build Coastguard Worker	end,
1561*387f9dfdSAndroid Build Coastguard Worker	socket = function (sock, prog)
1562*387f9dfdSAndroid Build Coastguard Worker		-- Expect socket type, if sock is string then assume it's
1563*387f9dfdSAndroid Build Coastguard Worker		-- an interface name (e.g. 'lo'), if it's a number then typecast it as a socket
1564*387f9dfdSAndroid Build Coastguard Worker		local ok, err
1565*387f9dfdSAndroid Build Coastguard Worker		if type(sock) == 'string' then
1566*387f9dfdSAndroid Build Coastguard Worker			local iface = assert(S.nl.getlink())[sock]
1567*387f9dfdSAndroid Build Coastguard Worker			assert(iface, sock..' is not interface name')
1568*387f9dfdSAndroid Build Coastguard Worker			sock, err = S.socket('packet', 'raw')
1569*387f9dfdSAndroid Build Coastguard Worker			assert(sock, tostring(err))
1570*387f9dfdSAndroid Build Coastguard Worker			ok, err = sock:bind(S.t.sockaddr_ll({protocol='all', ifindex=iface.index}))
1571*387f9dfdSAndroid Build Coastguard Worker			assert(ok, tostring(err))
1572*387f9dfdSAndroid Build Coastguard Worker		elseif type(sock) == 'number' then
1573*387f9dfdSAndroid Build Coastguard Worker			sock = S.t.fd(sock):nogc()
1574*387f9dfdSAndroid Build Coastguard Worker		elseif ffi.istype(S.t.fd, sock) then -- luacheck: ignore
1575*387f9dfdSAndroid Build Coastguard Worker			-- No cast required
1576*387f9dfdSAndroid Build Coastguard Worker		else
1577*387f9dfdSAndroid Build Coastguard Worker			return nil, 'socket must either be an fd number, an interface name, or an ljsyscall socket'
1578*387f9dfdSAndroid Build Coastguard Worker		end
1579*387f9dfdSAndroid Build Coastguard Worker		-- Load program and attach it to socket
1580*387f9dfdSAndroid Build Coastguard Worker		if type(prog) ~= 'table' then
1581*387f9dfdSAndroid Build Coastguard Worker			prog = compile(prog, {proto.skb})
1582*387f9dfdSAndroid Build Coastguard Worker		end
1583*387f9dfdSAndroid Build Coastguard Worker		local prog_fd, err, log = S.bpf_prog_load(S.c.BPF_PROG.SOCKET_FILTER, prog.insn, prog.pc)
1584*387f9dfdSAndroid Build Coastguard Worker		assert(prog_fd, tostring(err)..': '..tostring(log))
1585*387f9dfdSAndroid Build Coastguard Worker		assert(sock:setsockopt('socket', 'attach_bpf', prog_fd:getfd()))
1586*387f9dfdSAndroid Build Coastguard Worker		return prog_fd, err
1587*387f9dfdSAndroid Build Coastguard Worker	end,
1588*387f9dfdSAndroid Build Coastguard Worker	tracepoint = function(tp, prog, pid, cpu, group_fd)
1589*387f9dfdSAndroid Build Coastguard Worker		assert(trace_check_enabled())
1590*387f9dfdSAndroid Build Coastguard Worker		-- Return tracepoint instance if no program specified
1591*387f9dfdSAndroid Build Coastguard Worker		-- this allows free specialisation of arg0 to tracepoint type
1592*387f9dfdSAndroid Build Coastguard Worker		local probe = tracepoint_open(tp, pid, cpu, group_fd)
1593*387f9dfdSAndroid Build Coastguard Worker		-- Load the BPF program
1594*387f9dfdSAndroid Build Coastguard Worker		if prog then
1595*387f9dfdSAndroid Build Coastguard Worker			probe:bpf(prog)
1596*387f9dfdSAndroid Build Coastguard Worker		end
1597*387f9dfdSAndroid Build Coastguard Worker		return probe
1598*387f9dfdSAndroid Build Coastguard Worker	end,
1599*387f9dfdSAndroid Build Coastguard Worker	kprobe = function(tp, prog, retprobe, pid, cpu, group_fd)
1600*387f9dfdSAndroid Build Coastguard Worker		assert(trace_check_enabled())
1601*387f9dfdSAndroid Build Coastguard Worker		-- Open tracepoint and attach
1602*387f9dfdSAndroid Build Coastguard Worker		local pname, pdef = tp:match('([^:]+):(.+)')
1603*387f9dfdSAndroid Build Coastguard Worker		return trace_bpf('kprobe', pname, pdef, retprobe, prog, pid, cpu, group_fd)
1604*387f9dfdSAndroid Build Coastguard Worker	end,
1605*387f9dfdSAndroid Build Coastguard Worker	uprobe = function(tp, prog, retprobe, pid, cpu, group_fd)
1606*387f9dfdSAndroid Build Coastguard Worker		assert(trace_check_enabled())
1607*387f9dfdSAndroid Build Coastguard Worker		-- Translate symbol to address
1608*387f9dfdSAndroid Build Coastguard Worker		local obj, sym_want = tp:match('([^:]+):(.+)')
1609*387f9dfdSAndroid Build Coastguard Worker		if not S.statfs(obj) then return nil, S.t.error(S.c.E.NOENT) end
1610*387f9dfdSAndroid Build Coastguard Worker		-- Resolve Elf object (no support for anything else)
1611*387f9dfdSAndroid Build Coastguard Worker		local elf = require('bpf.elf').open(obj)
1612*387f9dfdSAndroid Build Coastguard Worker		local sym = elf:resolve(sym_want)
1613*387f9dfdSAndroid Build Coastguard Worker		if not sym then return nil, 'no such symbol' end
1614*387f9dfdSAndroid Build Coastguard Worker		sym = sym.st_value - elf:loadaddr()
1615*387f9dfdSAndroid Build Coastguard Worker		local sym_addr = string.format('%x%04x', tonumber(bit.rshift(sym, 32)),
1616*387f9dfdSAndroid Build Coastguard Worker		                                         tonumber(ffi.cast('uint32_t', sym)))
1617*387f9dfdSAndroid Build Coastguard Worker		-- Convert it to expected uprobe format
1618*387f9dfdSAndroid Build Coastguard Worker		local pname = string.format('%s_%s', obj:gsub('.*/', ''), sym_addr)
1619*387f9dfdSAndroid Build Coastguard Worker		local pdef = obj..':0x'..sym_addr
1620*387f9dfdSAndroid Build Coastguard Worker		return trace_bpf('uprobe', pname, pdef, retprobe, prog, pid, cpu, group_fd)
1621*387f9dfdSAndroid Build Coastguard Worker	end,
1622*387f9dfdSAndroid Build Coastguard Worker	tracelog = function(path)
1623*387f9dfdSAndroid Build Coastguard Worker		assert(trace_check_enabled())
1624*387f9dfdSAndroid Build Coastguard Worker		path = path or '/sys/kernel/debug/tracing/trace_pipe'
1625*387f9dfdSAndroid Build Coastguard Worker		return io.open(path, 'r')
1626*387f9dfdSAndroid Build Coastguard Worker	end,
1627*387f9dfdSAndroid Build Coastguard Worker	ntoh = builtins.ntoh, hton = builtins.hton,
1628*387f9dfdSAndroid Build Coastguard Worker}, {
1629*387f9dfdSAndroid Build Coastguard Worker	__call = function (_, prog) return compile(prog) end,
1630*387f9dfdSAndroid Build Coastguard Worker})
1631