def _call_mem_eq(i, **kwargs): if (not isinstance(i.src_vars[1], _mem.ConstVar) or not issubclass(i.src_vars[1].var_type, ctypes.Array)): raise TranslationError( i.starts_line, 'first arg to mem_eq must be const ctypes.Array') ret = [] # stack=None because we shouldn't need to allocate anything ret.extend(_lea(i, i.src_vars[2], bi.Reg.R2, stack=None)) false, done = _make_tmp_label(), _make_tmp_label() for off, v in enumerate(i.src_vars[1].val.value): ret.extend([ bi.Mov(bi.Mem(bi.Reg.R2, off, bi.Size.Byte), bi.Reg.R1), bi.JumpIfNotEqual(bi.Imm(v), bi.Reg.R1, false) ]) # If we made it here, it's a match ret.extend(_mov(bi.Imm(1), i.dst_vars[0])) ret.append(bi.Jump(done)) # if we jumped here, it's not a match ret.append(bi.Label(false)) ret.extend(_mov(bi.Imm(0), i.dst_vars[0])) ret.append(bi.Label(done)) return ret
def _call_packet_copy(i, **kwargs): # If you're thinking 'wow, this function looks complicated,' just go # take a look at kernel/bpf/verifier.c:find_good_pkt_pointers to see # the hoops that we're jumping through here. ret = [] fn, skb, dst_ptr, offset, num_bytes = i.src_vars # TODO: also support ptr to context? if not isinstance(skb, _mem.ArgVar): raise TranslationError( i.starts_line, 'First argument to packet_copy must be SkBuffContext argument') elif not isinstance(num_bytes, _mem.ConstVar): raise TranslationError( i.starts_line, 'Num bytes must not be dynamically defined for packet_copy') skb_data_mem = bi.Mem(_get_var_reg(skb), skb.var_type.data.offset, bi.Size.Word) skb_data_end_mem = bi.Mem(_get_var_reg(skb), skb.var_type.data_end.offset, bi.Size.Word) out_of_bounds = _make_tmp_label() # ret = _mov(dst_ptr, bi.Reg.R1) dst_ptr = _convert_var(dst_ptr) # %r2 = skb->data ret.append(bi.Mov(skb_data_mem, bi.Reg.R2)) # %r2 += offset if isinstance(offset, _mem.ConstVar): off_val = offset.val if hasattr(off_val, 'value'): off_val = off_val.value if off_val != 0: ret.append(bi.Add(bi.Imm(off_val), bi.Reg.R2)) else: ret.extend(_mov(offset, bi.Reg.R3)) ret.append(bi.Add(bi.Reg.R3, bi.Reg.R2)) # %r3 = %r2 ret.append(bi.Mov(bi.Reg.R2, bi.Reg.R3)) # %r2 += num_bytes ret.append(bi.Add(bi.Imm(num_bytes.val), bi.Reg.R2)) # %r4 = skb->data_end ret.append(bi.Mov(skb_data_end_mem, bi.Reg.R4)) # if skb->data + offset + num_bytes > skb->data_end: goto out_of_bounds ret.append(bi.JumpIfGreaterThan(bi.Reg.R4, bi.Reg.R2, out_of_bounds)) ret.extend(_memcpy_packet(i, dst_ptr, bi.Reg.R3, num_bytes.val)) ret.append(bi.Label(out_of_bounds)) return ret
def _binary_subscr_map(i, **kwargs): m, k, dv = i.src_vars[0], i.src_vars[1], i.dst_vars[0] if not isinstance(m, _mem.ConstVar): raise TranslationError(i.starts_line, 'Cannot subscript dynamically select map') found, done = _make_tmp_label(), _make_tmp_label() ret = [] ret.extend(_mov(bi.MapFdImm(m.val.fd), bi.Reg.R1)) ret.extend(_lea(i, k, bi.Reg.R2, **kwargs)) ret.extend([ bi.Call(bi.Imm(funcs.map_lookup_elem.num)), ]) if _is_ptr(dv.var_type): sz = _get_cdata_size(dv.var_type) ret.extend(_mov(bi.Reg.R0, dv)) else: ret.extend([ bi.JumpIfNotEqual(bi.Imm(0), bi.Reg.R0, found), ]) # Move default value dr = _get_var_reg(dv) ret.extend(_mov_const(dv.var_type, m.val.DEFAULT_VALUE, dr, dv.offset)) ret.extend([ bi.Jump(done), bi.Label(found), ]) # Primitives by value, others by reference if issubclass(dv.var_type, _ctypes._SimpleCData): sz = _get_cdata_size(dv.var_type) ret.extend(_mov(bi.Mem(bi.Reg.R0, 0, sz), dv)) else: ret.extend(_mov(bi.Reg.R0, dv)) ret.append(bi.Label(done)) return ret
def _compare_op(i, **kwargs): lhs, rhs = i.src_vars op = i.argval if op == '<': lhs, rhs = rhs, lhs op = '>' elif op == '<=': lhs, rhs = rhs, lhs op = '>=' jmp_type = { '>': bi.JumpIfGreaterThan, '>=': bi.JumpIfGreaterOrEqual, '==': bi.JumpIfEqual, '!=': bi.JumpIfNotEqual, }[op] true, done = _make_tmp_label(), _make_tmp_label() return (_mov(lhs, bi.Reg.R1) + _mov(rhs, bi.Reg.R2) + [jmp_type(bi.Reg.R1, bi.Reg.R2, true)] + _mov(bi.Imm(0), i.dst_vars[0]) + [bi.Jump(done)] + [bi.Label(true)] + _mov(bi.Imm(1), i.dst_vars[0]) + [bi.Label(done)])
def _label(i): return [bi.Label('label_{}'.format(i.offset))]