From 114a9e1da3cc4399fd1de28d752610a8333e060a Mon Sep 17 00:00:00 2001 From: Martin Teichmann <martin.teichmann@gmail.com> Date: Wed, 15 Feb 2023 08:51:38 +0000 Subject: [PATCH] supported fixed point numbers --- ebpfcat/arraymap.py | 14 ++- ebpfcat/ebpf.py | 232 +++++++++++++++++++++++++++++++++---------- ebpfcat/ebpf_test.py | 173 ++++++++++++++++++++++++++++++-- ebpfcat/hashmap.py | 1 + 4 files changed, 353 insertions(+), 67 deletions(-) diff --git a/ebpfcat/arraymap.py b/ebpfcat/arraymap.py index b20934c..05fadec 100644 --- a/ebpfcat/arraymap.py +++ b/ebpfcat/arraymap.py @@ -19,7 +19,7 @@ from itertools import chain from mmap import mmap from struct import pack_into, unpack_from, calcsize -from .ebpf import FuncId, Map, MemoryDesc, Opcode, SubProgram +from .ebpf import Expression, FuncId, Map, MemoryDesc, Opcode, SubProgram from .bpf import create_map, lookup_elem, MapType, MapFlags, update_elem @@ -29,6 +29,7 @@ class ArrayGlobalVarDesc(MemoryDesc): def __init__(self, map, fmt): self.map = map self.fmt = fmt + self.fixed = fmt == "f" def fmt_addr(self, ebpf): return self.fmt, ebpf.__dict__[self.name] @@ -42,7 +43,10 @@ class ArrayGlobalVarDesc(MemoryDesc): if instance.ebpf.loaded: fmt, addr = self.fmt_addr(instance) data = instance.ebpf.__dict__[self.map.name].data - ret = unpack_from(fmt, data, addr) + if fmt == "f": + return unpack_from("q", data, addr)[0] / Expression.FIXED_BASE + else: + ret = unpack_from(fmt, data, addr) if len(ret) == 1: return ret[0] else: @@ -53,6 +57,9 @@ class ArrayGlobalVarDesc(MemoryDesc): def __set__(self, instance, value): if instance.ebpf.loaded: fmt, addr = self.fmt_addr(instance) + if fmt == "f": + fmt = "q" + value = int(value * Expression.FIXED_BASE) if not isinstance(value, tuple): value = value, pack_into(fmt, instance.ebpf.__dict__[self.map.name].data, @@ -80,7 +87,8 @@ class ArrayMap(Map): for prog in chain([ebpf], ebpf.subprograms): for k, v in prog.__class__.__dict__.items(): if isinstance(v, ArrayGlobalVarDesc): - collection.append((calcsize(v.fmt), prog, k)) + collection.append((8 if v.fmt == "f" else calcsize(v.fmt), + prog, k)) collection.sort(key=lambda t: t[0], reverse=True) position = 0 for size, prog, name in collection: diff --git a/ebpfcat/ebpf.py b/ebpfcat/ebpf.py index 39abe09..0750830 100644 --- a/ebpfcat/ebpf.py +++ b/ebpfcat/ebpf.py @@ -18,6 +18,7 @@ from abc import ABC, abstractmethod from collections import namedtuple from contextlib import contextmanager, ExitStack +from operator import index from struct import pack, unpack, calcsize from enum import Enum @@ -268,10 +269,18 @@ class AssembleError(Exception): def comparison(uposop, unegop, sposop, snegop): def ret(self, value): + valuefixed, value = fixedvalue(value) + myself = self + if self.fixed != valuefixed: + if self.fixed: + value = value * self.FIXED_BASE + else: + myself = self * self.FIXED_BASE + if self.signed or issigned(value): - return SimpleComparison(self.ebpf, self, value, (sposop, snegop)) + return SimpleComparison(self.ebpf, myself, value, (sposop, snegop)) else: - return SimpleComparison(self.ebpf, self, value, (uposop, unegop)) + return SimpleComparison(self.ebpf, myself, value, (uposop, unegop)) return ret @@ -429,39 +438,112 @@ def issigned(value): return value < 0 -def binary(opcode): - def ret(self, value): - return Binary(self.ebpf, self, value, opcode, - self.signed or issigned(value), False) - return ret - -def rbinary(opcode): - def ret(self, value): - return ReverseBinary(self.ebpf, value, self, opcode, value < 0, False) - return ret +def fixedvalue(value): + try: + return False, index(value) + except TypeError: + try: + return True, int(float(value) * Expression.FIXED_BASE) + except TypeError: + return value.fixed, value class Expression: """the base class for all numerical expressions""" - __radd__ = __add__ = binary(Opcode.ADD) - __sub__ = binary(Opcode.SUB) - __rsub__ = rbinary(Opcode.SUB) - __rmul__ = __mul__ = binary(Opcode.MUL) - __floordiv__ = binary(Opcode.DIV) - __rfloordiv__ = rbinary(Opcode.DIV) - __ror__ = __or__ = binary(Opcode.OR) - __lshift__ = binary(Opcode.LSH) - __rlshift__ = rbinary(Opcode.LSH) - __rrshift__ = rbinary(Opcode.RSH) - __mod__ = binary(Opcode.MOD) - __rmod__ = rbinary(Opcode.MOD) - __rxor__ = __xor__ = binary(Opcode.XOR) + + FIXED_BASE = 100000 + + def _binary(self, value, opcode): + return Binary(self.ebpf, self, value, opcode, + self.signed or issigned(value), False) + + __ror__ = __or__ = lambda self, value: self._binary(value, Opcode.OR) + __lshift__ = lambda self, value: self._binary(value, Opcode.LSH) + __rxor__ = __xor__ = lambda self, value: self._binary(value, Opcode.XOR) __gt__ = comparison(Opcode.JGT, Opcode.JLE, Opcode.JSGT, Opcode.JSLE) __ge__ = comparison(Opcode.JGE, Opcode.JLT, Opcode.JSGE, Opcode.JSLT) __lt__ = comparison(Opcode.JLT, Opcode.JGE, Opcode.JSLT, Opcode.JSGE) __le__ = comparison(Opcode.JLE, Opcode.JGT, Opcode.JSLE, Opcode.JSGT) + def _sum(self, value, opcode): + valuefixed, value = fixedvalue(value) + myself = self + if self.fixed != valuefixed: + if self.fixed: + value = value * self.FIXED_BASE + else: + myself = self * self.FIXED_BASE + + return Binary(self.ebpf, myself, value, opcode, + self.signed or issigned(value), self.fixed or valuefixed) + + def _rsum(self, value, opcode): + valuefixed, value = fixedvalue(value) + myself = self + if self.fixed != valuefixed: + if self.fixed: + value = value * self.FIXED_BASE + else: + myself = self * self.FIXED_BASE + + return ReverseBinary( + self.ebpf, value, myself, opcode, + self.signed or issigned(value), self.fixed or valuefixed) + + __radd__ = __add__ = lambda self, value: self._sum(value, Opcode.ADD) + __sub__ = lambda self, value: self._sum(value, Opcode.SUB) + __rsub__ = lambda self, value: self._rsum(value, Opcode.SUB) + __mod__ = lambda self, value: self._sum(value, Opcode.MOD) + __rmod__ = lambda self, value: self._rsum(value, Opcode.MOD) + + def __mul__(self, value): + valuefixed, value = fixedvalue(value) + ret = Binary(self.ebpf, self, value, Opcode.MUL, + self.signed or issigned(value), self.fixed or valuefixed) + if self.fixed and valuefixed: + ret = ret / self.FIXED_BASE + return ret + __rmul__ = __mul__ + + def __truediv__(self, value): + valuefixed, value = fixedvalue(value) + myself = self + if not self.fixed and valuefixed: + myself = myself * self.FIXED_BASE ** 2 + elif self.fixed == valuefixed: + myself = myself * self.FIXED_BASE + + return Binary(self.ebpf, myself, value, Opcode.DIV, + self.signed or issigned(value), True) + + def __rtruediv__(self, value): + if self.fixed: + value = int(value * self.FIXED_BASE ** 2) + else: + value = int(value * self.FIXED_BASE) + return ReverseBinary(self.ebpf, value, self, Opcode.DIV, + self.signed or issigned(value), True) + + def __floordiv__(self, value): + valuefixed, value = fixedvalue(value) + myself = self + if not self.fixed and valuefixed: + myself = myself * self.FIXED_BASE + elif self.fixed and not valuefixed: + value = value * self.FIXED_BASE + + return Binary(self.ebpf, myself, value, Opcode.DIV, + self.signed or issigned(value), False) + + def __rfloordiv__(self, value): + if self.fixed: + value = int(value * self.FIXED_BASE) + else: + value = int(value) + return ReverseBinary(self.ebpf, value, self, Opcode.DIV, + self.signed or issigned(value), False) + def __rshift__(self, value): opcode = Opcode.ARSH if self.signed else Opcode.RSH return Binary(self.ebpf, self, value, opcode, self.signed, False) @@ -470,13 +552,16 @@ class Expression: opcode = Opcode.ARSH if value < 0 else Opcode.RSH return ReverseBinary(self.ebpf, value, self, opcode, value < 0, False) + def __rlshift__(self, value): + return ReverseBinary(self.ebpf, value, self, Opcode.LSH, + value < 0, False) + def __and__(self, value): return AndExpression(self.ebpf, self, value) def __ne__(self, value): - return SimpleComparison( - self.ebpf, self, value, - (Opcode.JNE, Opcode.JEQ, Opcode.JNE, Opcode.JEQ)) + return SimpleComparison(self.ebpf, self, value, + (Opcode.JNE, Opcode.JEQ)) def __eq__(self, value): return ~(self != value) @@ -626,6 +711,7 @@ class Negate(Expression): self.ebpf = ebpf self.arg = arg self.signed = True + self.fixed = arg.fixed @contextmanager def calculate(self, dst, long, force=False): @@ -641,12 +727,13 @@ class Absolute(Expression): def __init__(self, ebpf, arg): self.ebpf = ebpf self.arg = arg + self.fixed = arg.fixed @contextmanager def calculate(self, dst, long, force=False): with self.arg.calculate(dst, long, force) as (dst, long): - with self.ebpf.r[dst] < 0: - self.ebpf.r[dst] = -self.ebpf.r[dst] + with self.ebpf.sr[dst] < 0: + self.ebpf.sr[dst] = -self.ebpf.sr[dst] yield dst, long def contains(self, no): @@ -662,18 +749,18 @@ class Sum(Binary): super().__init__(ebpf, left, right, Opcode.ADD, right < 0, False) def __add__(self, value): - if isinstance(value, Expression): + try: + return Sum(self.ebpf, self.left, self.right + index(value)) + except TypeError: return super().__add__(value) - else: - return Sum(self.ebpf, self.left, self.right + value) __radd__ = __add__ def __sub__(self, value): - if isinstance(value, Expression): - return super().__sub__(value) - else: - return Sum(self.ebpf, self.left, self.right - value) + try: + return Sum(self.ebpf, self.left, self.right - index(value)) + except TypeError: + return super().__add__(value) class AndExpression(Binary): @@ -733,25 +820,30 @@ class Register(Expression): """represent one EBPF register""" offset = 0 - def __init__(self, no, ebpf, long, signed): + def __init__(self, no, ebpf, long, signed, fixed=False): self.no = no self.ebpf = ebpf self.long = long self.signed = signed + self.fixed = fixed def __add__(self, value): - if isinstance(value, Expression) or not self.long: - return super().__add__(value) - else: - return Sum(self.ebpf, self, value) + if self.long and not self.fixed: + try: + return Sum(self.ebpf, self, index(value)) + except TypeError: + pass + return super().__add__(value) __radd__ = __add__ def __sub__(self, value): - if isinstance(value, Expression) or not self.long: - return super().__sub__(value) - else: - return Sum(self.ebpf, self, -value) + if self.long and not self.fixed: + try: + return Sum(self.ebpf, self, -index(value)) + except TypeError: + pass + return super().__sub__(value) @contextmanager def calculate(self, dst, long, force=False): @@ -778,7 +870,7 @@ class Memory(Expression): bits_to_opcode = {32: Opcode.W, 16: Opcode.H, 8: Opcode.B, 64: Opcode.DW} fmt_to_opcode = {'I': Opcode.W, 'H': Opcode.H, 'B': Opcode.B, 'Q': Opcode.DW, 'i': Opcode.W, 'h': Opcode.H, 'b': Opcode.B, 'q': Opcode.DW, - 'A': Opcode.W} + 'A': Opcode.W, 'f': Opcode.DW} def __init__(self, ebpf, fmt, address): self.ebpf = ebpf @@ -828,6 +920,10 @@ class Memory(Expression): def signed(self): return isinstance(self.fmt, str) and self.fmt.islower() + @property + def fixed(self): + return isinstance(self.fmt, str) and self.fmt == "f" + def __invert__(self): if not isinstance(self.fmt, tuple) or self.fmt[1] != 1: return NotImplemented @@ -880,6 +976,8 @@ class MemoryDesc: elif isinstance(value, IAdd): value = value.value if not isinstance(value, Expression): + if self.fixed: + value = int(value * self.FIXED_BASE) with ebpf.get_free_register(None) as src: ebpf.r[src] = value ebpf.append(Opcode.XADD + bits, self.base_register, @@ -889,10 +987,16 @@ class MemoryDesc: elif isinstance(value, Expression): opcode = Opcode.STX else: + if self.fixed: + value = int(value * Expression.FIXED_BASE) ebpf.append(Opcode.ST + bits, self.base_register, 0, addr, value) return - with value.calculate(None, isinstance(fmt, str) and fmt in 'qQ' + if self.fmt == "f" and not value.fixed: + value = value * Expression.FIXED_BASE + elif self.fmt != "f" and value.fixed: + value = value / Expression.FIXED_BASE + with value.calculate(None, isinstance(fmt, str) and fmt in 'qQf' ) as (src, _): ebpf.append(opcode + bits, self.base_register, src, addr, 0) @@ -903,6 +1007,7 @@ class LocalVar(MemoryDesc): def __init__(self, fmt='I'): self.fmt = fmt + self.fixed = fmt == "f" def __set_name__(self, owner, name): if isinstance(self.fmt, str): @@ -936,7 +1041,9 @@ class MemoryMap: offset = 0 if isinstance(value, IAdd): value = value.value - if isinstance(value, int): + if self.fmt == "f": + value = int(value * self.FIXED_BASE) + if not isinstance(value, Expression): with self.ebpf.get_free_register(None) as src: self.ebpf.r[src] = value self.ebpf.append( @@ -947,6 +1054,8 @@ class MemoryMap: elif isinstance(value, Expression): opcode = Opcode.STX else: + if self.fmt == "f": + value = int(value * self.FIXED_BASE) self.ebpf.append(Opcode.ST + Memory.fmt_to_opcode[self.fmt], dst, 0, offset, value) return @@ -975,6 +1084,7 @@ class PseudoFd(Expression): def __init__(self, ebpf, fd): self.ebpf = ebpf self.fd = fd + self.fixed = False @contextmanager def calculate(self, dst, long, force=False): @@ -988,6 +1098,7 @@ class ktime(Expression): """a function that returns the current ktime in ns""" def __init__(self, ebpf): self.ebpf = ebpf + self.fixed = False @contextmanager def calculate(self, dst, long, force=False): @@ -1030,27 +1141,34 @@ class RegisterDesc: class RegisterArray: - def __init__(self, ebpf, long, signed): + def __init__(self, ebpf, long, signed, fixed=False): self.ebpf = ebpf self.long = long self.signed = signed + self.fixed = fixed def __setitem__(self, no, value): self.ebpf.owners.add(no) if isinstance(value, Expression): + if self.fixed and not value.fixed: + value = value * Expression.FIXED_BASE + if not self.fixed and value.fixed: + value = value / Expression.FIXED_BASE with value.calculate(no, self.long, True): pass else: + if self.fixed: + value = int(value * Expression.FIXED_BASE) self.ebpf._load_value(no, value) def __getitem__(self, no): - return Register(no, self.ebpf, self.long, self.signed) + return Register(no, self.ebpf, self.long, self.signed, self.fixed) class Temporary(Register): - def __init__(self, ebpf, long, signed): - super().__init__(None, ebpf, long, signed) + def __init__(self, ebpf, long, signed, fixed): + super().__init__(None, ebpf, long, signed, fixed) self.nos = [] self.gfrs = [] @@ -1077,7 +1195,7 @@ class TemporaryDesc(RegisterDesc): ret = instance.__dict__.get(self.name, None) if ret is None: ret = instance.__dict__[self.name] = \ - Temporary(instance, arr.long, arr.signed) + Temporary(instance, arr.long, arr.signed, arr.fixed) return ret def __set__(self, instance, value): @@ -1118,11 +1236,13 @@ class EBPF: self.mh = MemoryMap(self, "h") self.mi = MemoryMap(self, "i") self.mq = MemoryMap(self, "q") + self.mf = MemoryMap(self, "f") self.r = RegisterArray(self, True, False) self.sr = RegisterArray(self, True, True) self.w = RegisterArray(self, False, False) self.sw = RegisterArray(self, False, True) + self.f = RegisterArray(self, True, True, True) self.owners = {1, 10} @@ -1247,6 +1367,7 @@ class EBPF: stmp = TemporaryDesc(None, "sr") wtmp = TemporaryDesc(None, "w") swtmp = TemporaryDesc(None, "sw") + ftmp = TemporaryDesc(None, "f") for i in range(11): @@ -1261,6 +1382,9 @@ for i in range(10): for i in range(10): setattr(EBPF, f"sw{i}", RegisterDesc(i, "sw")) +for i in range(10): + setattr(EBPF, f"f{i}", RegisterDesc(i, "f")) + class SubProgram: stack = 0 diff --git a/ebpfcat/ebpf_test.py b/ebpfcat/ebpf_test.py index 19fadf2..0ffdac5 100644 --- a/ebpfcat/ebpf_test.py +++ b/ebpfcat/ebpf_test.py @@ -162,24 +162,142 @@ class Tests(TestCase): Instruction(opcode=O.LONG+O.RSH, dst=5, src=0, off=0, imm=2), ]) + def test_fixed(self): + e = EBPF() + e.owners = {0, 1, 2, 3, 4, 5, 6} + e.f1 = e.r2 + 3 + e.f3 = e.r4 + 3.5 + e.f5 = e.f6 + 3 + e.r1 = e.r2 + e.f3 + e.f4 = e.f5 + e.f6 + e.r1 = 2 - e.f2 + e.r3 = 3.4 - e.r4 + e.r5 = e.f6 % 4 + + e.f1 = e.r2 * 3 + e.f3 = e.r4 * 3.5 + e.f5 = e.f6 * 3 + e.r1 = e.r2 * e.f3 + e.f4 = e.f5 * e.f6 + + e.f1 = e.r2 / 3 + e.f3 = e.r4 / 3.5 + e.f5 = e.f6 / 3 + e.r1 = e.r2 / e.f3 + e.f4 = e.f5 / e.f6 + + e.f1 = e.r2 // 3 + e.f3 = e.r4 // 3.5 + e.f5 = e.f6 // 3 + e.r1 = e.r2 // e.f3 + e.f4 = e.f5 // e.f6 + + self.maxDiff = None + self.assertEqual(e.opcodes, [ + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.ADD+O.LONG, dst=1, src=0, off=0, imm=3), + Instruction(opcode=O.MUL+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=3, src=4, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=3, src=0, off=0, imm=100000), + Instruction(opcode=O.ADD+O.LONG, dst=3, src=0, off=0, imm=350000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=5, src=6, off=0, imm=0), + Instruction(opcode=O.ADD+O.LONG, dst=5, src=0, off=0, imm=300000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.ADD+O.LONG, dst=1, src=3, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=4, src=5, off=0, imm=0), + Instruction(opcode=O.REG+O.ADD+O.LONG, dst=4, src=6, off=0, imm=0), + Instruction(opcode=O.MOV+O.LONG, dst=1, src=0, off=0, imm=200000), + Instruction(opcode=O.REG+O.SUB+O.LONG, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.LONG+O.DIV, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.MOV+O.LONG, dst=3, src=0, off=0, imm=340000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=7, src=4, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=7, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.SUB+O.LONG, dst=3, src=7, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=3, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.LONG+O.MOV, dst=5, src=6, off=0, imm=0), + Instruction(opcode=O.LONG+O.MOD, dst=5, src=0, off=0, imm=400000), + Instruction(opcode=O.LONG+O.DIV, dst=5, src=0, off=0, imm=100000), + + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=1, src=0, off=0, imm=3), + Instruction(opcode=O.LONG+O.MUL, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=3, src=4, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=3, src=0, off=0, imm=350000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=5, src=6, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=5, src=0, off=0, imm=3), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.REG+O.LONG+O.MUL, dst=1, src=3, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=4, src=5, off=0, imm=0), + Instruction(opcode=O.REG+O.LONG+O.MUL, dst=4, src=6, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=4, src=0, off=0, imm=100000), + + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.DIV+O.LONG, dst=1, src=0, off=0, imm=3), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=3, src=4, off=0, imm=0), + Instruction(opcode=O.DW, dst=7, src=0, off=0, imm=1410065408), + Instruction(opcode=O.W, dst=0, src=0, off=0, imm=2), + Instruction(opcode=O.MUL+O.REG+O.LONG, dst=3, src=7, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=3, src=0, off=0, imm=350000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=5, src=6, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=5, src=0, off=0, imm=3), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.DW, dst=7, src=0, off=0, imm=1410065408), + Instruction(opcode=O.W, dst=0, src=0, off=0, imm=2), + Instruction(opcode=O.REG+O.LONG+O.MUL, dst=1, src=7, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG+O.REG, dst=1, src=3, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=4, src=5, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=4, src=0, off=0, imm=100000), + Instruction(opcode=O.DIV+O.LONG+O.REG, dst=4, src=6, off=0, imm=0), + + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=1, src=0, off=0, imm=3), + Instruction(opcode=O.MUL+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=3, src=4, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=3, src=0, off=0, imm=100000), + Instruction(opcode=O.DIV+O.LONG, dst=3, src=0, off=0, imm=350000), + Instruction(opcode=O.MUL+O.LONG, dst=3, src=0, off=0, imm=100000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=5, src=6, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=5, src=0, off=0, imm=300000), + Instruction(opcode=O.MUL+O.LONG, dst=5, src=0, off=0, imm=100000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=1, src=2, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=1, src=0, off=0, imm=100000), + Instruction(opcode=O.DIV+O.LONG+O.REG, dst=1, src=3, off=0, imm=0), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=4, src=5, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG+O.REG, dst=4, src=6, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=4, src=0, off=0, imm=100000), + ]) + def test_local(self): class Local(EBPF): a = LocalVar('b') b = LocalVar('H') c = LocalVar('i') d = LocalVar('Q') + lf = LocalVar('f') e = Local(ProgType.XDP, "GPL") e.a = 5 e.b = e.c >> 3 e.d = e.r1 + e.lf = 7 + e.b = e.f1 self.assertEqual(e.opcodes, [ Instruction(opcode=O.B+O.ST, dst=10, src=0, off=-1, imm=5), Instruction(opcode=O.W+O.LD, dst=0, src=10, off=-8, imm=0), Instruction(opcode=O.ARSH, dst=0, src=0, off=0, imm=3), Instruction(opcode=O.REG+O.STX, dst=10, src=0, off=-4, imm=0), - Instruction(opcode=O.DW+O.STX, dst=10, src=1, off=-16, imm=0)]) + Instruction(opcode=O.DW+O.STX, dst=10, src=1, off=-16, imm=0), + Instruction(opcode=O.DW+O.ST, dst=10, src=0, off=-20, imm=700000), + Instruction(opcode=O.LONG+O.REG+O.MOV, dst=0, src=1, off=0, imm=0), + Instruction(opcode=O.DIV, dst=0, src=0, off=0, imm=100000), + Instruction(opcode=O.REG+O.STX, dst=10, src=0, off=-4, imm=0), + ]) def test_local_bits(self): class Local(EBPF): @@ -375,7 +493,7 @@ class Tests(TestCase): def test_with(self): e = EBPF() - e.owners = set(range(11)) + e.owners = set(range(9)) with e.r2 > 3 as Else: e.r2 = 5 with Else: @@ -386,8 +504,16 @@ class Tests(TestCase): e.r5 = 7 with Else: e.r7 = 8 - self.assertEqual(e.opcodes, - [Instruction(opcode=0xb5, dst=2, src=0, off=2, imm=3), + with e.f4 > 3: + pass + with 3 > e.f4: + pass + with e.r4 > 3.5: + pass + with e.f4 > e.f2: + pass + self.assertEqual(e.opcodes, [ + Instruction(opcode=0xb5, dst=2, src=0, off=2, imm=3), Instruction(opcode=0xb7, dst=2, src=0, off=0, imm=5), Instruction(opcode=0x5, dst=0, src=0, off=1, imm=0), Instruction(opcode=O.MOV+O.LONG, dst=6, src=0, off=0, imm=7), @@ -396,7 +522,14 @@ class Tests(TestCase): Instruction(opcode=O.JLE, dst=4, src=0, off=2, imm=3), Instruction(opcode=O.MOV+O.LONG, dst=5, src=0, off=0, imm=7), Instruction(opcode=O.JMP, dst=0, src=0, off=1, imm=0), - Instruction(opcode=O.MOV+O.LONG, dst=7, src=0, off=0, imm=8)]) + Instruction(opcode=O.MOV+O.LONG, dst=7, src=0, off=0, imm=8), + Instruction(opcode=O.JSLE, dst=4, src=0, off=0, imm=300000), + Instruction(opcode=O.JSGE, dst=4, src=0, off=0, imm=300000), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=9, src=4, off=0, imm=0), + Instruction(opcode=O.MUL+O.LONG, dst=9, src=0, off=0, imm=100000), + Instruction(opcode=O.JLE, dst=9, src=0, off=0, imm=350000), + Instruction(opcode=O.REG+O.JSLE, dst=4, src=2, off=0, imm=0), + ]) def test_with_inversion(self): e = EBPF() @@ -602,10 +735,15 @@ class Tests(TestCase): def test_absolute(self): e = EBPF() e.r7 = abs(e.r1) + e.f3 = abs(e.f1) self.assertEqual(e.opcodes, [ Instruction(opcode=O.LONG+O.REG+O.MOV, dst=7, src=1, off=0, imm=0), - Instruction(opcode=O.JGE, dst=7, src=0, off=1, imm=0), - Instruction(opcode=O.LONG+O.NEG, dst=7, src=0, off=0, imm=0)]) + Instruction(opcode=O.JSGE, dst=7, src=0, off=1, imm=0), + Instruction(opcode=O.LONG+O.NEG, dst=7, src=0, off=0, imm=0), + Instruction(opcode=O.REG+O.MOV+O.LONG, dst=3, src=1, off=0, imm=0), + Instruction(opcode=O.JSGE, dst=3, src=0, off=1, imm=0), + Instruction(opcode=O.NEG+O.LONG, dst=3, src=0, off=0, imm=0), + ]) def test_jump_data(self): e = EBPF() @@ -712,6 +850,10 @@ class Tests(TestCase): e.r7 = e.tmp e.tmp = 2 e.r3 = e.tmp + with e.ftmp: + e.ftmp = 3 + e.r3 = e.ftmp + e.ftmp = e.r3 * 3.5 self.assertEqual(e.opcodes, [ Instruction(opcode=O.MOV+O.LONG, dst=0, src=0, off=0, imm=7), Instruction(opcode=O.MOV+O.LONG, dst=2, src=0, off=0, imm=3), @@ -719,7 +861,12 @@ class Tests(TestCase): Instruction(opcode=O.MOV+O.LONG, dst=4, src=0, off=0, imm=5), Instruction(opcode=O.MOV+O.LONG+O.REG, dst=7, src=4, off=0, imm=0), Instruction(opcode=O.MOV+O.LONG, dst=2, src=0, off=0, imm=2), - Instruction(opcode=O.MOV+O.LONG+O.REG, dst=3, src=2, off=0, imm=0) + Instruction(opcode=O.MOV+O.LONG+O.REG, dst=3, src=2, off=0, imm=0), + Instruction(opcode=O.MOV+O.LONG, dst=2, src=0, off=0, imm=300000), + Instruction(opcode=O.MOV+O.REG+O.LONG, dst=3, src=2, off=0, imm=0), + Instruction(opcode=O.DIV+O.LONG, dst=3, src=0, off=0, imm=100000), + Instruction(opcode=O.MOV+O.REG+O.LONG, dst=2, src=3, off=0, imm=0), + Instruction(opcode=O.LONG+O.MUL, dst=2, src=0, off=0, imm=350000), ]) def test_ktime(self): @@ -775,15 +922,18 @@ class KernelTests(TestCase): class Global(EBPF): map = ArrayMap() ar = map.globalVar() - aw = map.globalVar() + aw = map.globalVar("h") class Sub(SubProgram): br = Global.map.globalVar() - bw = Global.map.globalVar() + bw = Global.map.globalVar("h") + bf = Global.map.globalVar("f") def program(self): + self.bw = 4 self.br -= -33 self.bw = self.br + 3 + self.bf = self.br / 3.5 + self.bf s1 = Sub() s2 = Sub() @@ -801,9 +951,11 @@ class KernelTests(TestCase): self.assertEqual(e.aw, 11) self.assertEqual(s1.br, 33) self.assertEqual(s1.bw, 36) + self.assertEqual(s2.bf, 9.42857) s1.br = 3 s2.br *= 5 e.ar = 1111 + s2.bf = 1.3 self.assertEqual(e.ar, 1111) self.assertEqual(e.aw, 11) self.assertEqual(s1.br, 3) @@ -817,6 +969,7 @@ class KernelTests(TestCase): self.assertEqual(s1.bw, 39) self.assertEqual(s2.br, 198) self.assertEqual(s2.bw, 201) + self.assertEqual(s2.bf, 57.87142) def test_minimal(self): class Local(EBPF): diff --git a/ebpfcat/hashmap.py b/ebpfcat/hashmap.py index aacea52..8e5e61c 100644 --- a/ebpfcat/hashmap.py +++ b/ebpfcat/hashmap.py @@ -28,6 +28,7 @@ class HashGlobalVar(Expression): self.count = count self.fmt = fmt self.signed = fmt.islower() + self.fixed = fmt == "f" @contextmanager def get_address(self, dst, long, force=False): -- GitLab