package ebpf
|
|
|
|
import "fmt"
|
|
|
|
// Jump skips the following Skip instructions in the program.
|
|
type Jump struct {
|
|
Offset uint16
|
|
}
|
|
|
|
// Assemble implements the Instruction Assemble method.
|
|
func (a Jump) Assemble() (RawInstruction, error) {
|
|
return RawInstruction{
|
|
Op: opClassJump | jumpOp,
|
|
Offset: int16(a.Offset),
|
|
}, nil
|
|
}
|
|
|
|
// String returns the instruction in assembler notation.
|
|
func (a Jump) String() string {
|
|
return fmt.Sprintf("ja +%d", a.Offset)
|
|
}
|
|
|
|
// JumpTest is a comparison operator used in conditional jumps.
|
|
type JumpTest uint8
|
|
|
|
// Supported operators for conditional jumps.
|
|
const (
|
|
JumpEqual JumpTest = iota // K == A
|
|
JumpGreater // K > A
|
|
JumpGreaterOrEqual // K >= A
|
|
JumpSet // K & A
|
|
JumpNotEqual // K != A
|
|
JumpSignedGreater // K > A
|
|
JumpSignedGreaterOrEqual // K >= A
|
|
JumpLess // K < A
|
|
JumpLessOrEqual // K <= A
|
|
JumpSignedLess // K < A
|
|
JumpSignedLessOrEqual // K <= A
|
|
)
|
|
|
|
func (cond JumpTest) Match(dst, src uint64) bool {
|
|
switch cond {
|
|
case JumpEqual:
|
|
return dst == src
|
|
case JumpGreater:
|
|
return dst > src
|
|
case JumpGreaterOrEqual:
|
|
return dst >= src
|
|
case JumpSet:
|
|
return dst&src != 0
|
|
case JumpNotEqual:
|
|
return dst != src
|
|
case JumpSignedGreater:
|
|
return int64(dst) > int64(src)
|
|
case JumpSignedGreaterOrEqual:
|
|
return int64(dst) >= int64(src)
|
|
case JumpLess:
|
|
return dst < src
|
|
case JumpLessOrEqual:
|
|
return dst <= src
|
|
case JumpSignedLess:
|
|
return int64(dst) < int64(src)
|
|
case JumpSignedLessOrEqual:
|
|
return int64(dst) <= int64(src)
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (cond JumpTest) String() string {
|
|
switch cond {
|
|
case JumpEqual:
|
|
return "jeq"
|
|
case JumpGreater:
|
|
return "jgt"
|
|
case JumpGreaterOrEqual:
|
|
return "jge"
|
|
case JumpSet:
|
|
return "jset"
|
|
case JumpNotEqual:
|
|
return "jne"
|
|
case JumpSignedGreater:
|
|
return "jsgt"
|
|
case JumpSignedGreaterOrEqual:
|
|
return "jsge"
|
|
case JumpLess:
|
|
return "jlt"
|
|
case JumpLessOrEqual:
|
|
return "jle"
|
|
case JumpSignedLess:
|
|
return "jslt"
|
|
case JumpSignedLessOrEqual:
|
|
return "jsle"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func (cond JumpTest) CFormat() string {
|
|
switch cond {
|
|
case JumpEqual:
|
|
return "%s == %s"
|
|
case JumpGreater:
|
|
return "%s > %s"
|
|
case JumpGreaterOrEqual:
|
|
return "%s >= %s"
|
|
case JumpSet:
|
|
return "%s & %s"
|
|
case JumpNotEqual:
|
|
return "%s != %s"
|
|
case JumpSignedGreater:
|
|
return "(int64_t)(%s) > (int64_t)(%s)"
|
|
case JumpSignedGreaterOrEqual:
|
|
return "(int64_t)(%s) >= (int64_t)(%s)"
|
|
case JumpLess:
|
|
return "%s < %s"
|
|
case JumpLessOrEqual:
|
|
return "%s <= %s"
|
|
case JumpSignedLess:
|
|
return "(int64_t)(%s) < (int64_t)(%s)"
|
|
case JumpSignedLessOrEqual:
|
|
return "(int64_t)(%s) <= (int64_t)(%s)"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|
|
|
|
func jumpOpToTest(op Opcode) JumpTest {
|
|
switch op {
|
|
case jumpOpEqual:
|
|
return JumpEqual
|
|
case jumpOpGreater:
|
|
return JumpGreater
|
|
case jumpOpGreaterOrEqual:
|
|
return JumpGreaterOrEqual
|
|
case jumpOpSet:
|
|
return JumpSet
|
|
case jumpOpNotEqual:
|
|
return JumpNotEqual
|
|
case jumpOpSignedGreater:
|
|
return JumpSignedGreater
|
|
case jumpOpSignedGreaterOrEqual:
|
|
return JumpSignedGreaterOrEqual
|
|
case jumpOpLess:
|
|
return JumpLess
|
|
case jumpOpLessOrEqual:
|
|
return JumpLessOrEqual
|
|
case jumpOpSignedLess:
|
|
return JumpSignedLess
|
|
case jumpOpSignedLessOrEqual:
|
|
return JumpLessOrEqual
|
|
default:
|
|
return 0xff
|
|
}
|
|
}
|
|
|
|
// JumpIf performs a conditional jump.
|
|
type JumpIf struct {
|
|
Cond JumpTest
|
|
Dst Register
|
|
Value uint32
|
|
Offset uint16
|
|
}
|
|
|
|
func (a JumpIf) Assemble() (RawInstruction, error) {
|
|
return jumpToRaw(a.Cond, true, a.Dst, a.Value, a.Offset)
|
|
}
|
|
|
|
func (a JumpIf) String() string {
|
|
return fmt.Sprintf("%s %s, %d, +%d", a.Cond, a.Dst, a.Value, a.Offset)
|
|
}
|
|
|
|
type JumpIfX struct {
|
|
Cond JumpTest
|
|
Dst, Src Register
|
|
Offset uint16
|
|
}
|
|
|
|
func (a JumpIfX) Assemble() (RawInstruction, error) {
|
|
return jumpToRaw(a.Cond, false, a.Dst, uint32(a.Src), a.Offset)
|
|
}
|
|
|
|
func (a JumpIfX) String() string {
|
|
return fmt.Sprintf("%s %s, %s, +%d", a.Cond, a.Dst, a.Src, a.Offset)
|
|
}
|
|
|
|
func jumpToRaw(test JumpTest, immediate bool, dst Register, value uint32, offset uint16) (RawInstruction, error) {
|
|
var (
|
|
cond Opcode
|
|
)
|
|
switch test {
|
|
case JumpEqual:
|
|
cond = jumpOpEqual
|
|
case JumpGreater:
|
|
cond = jumpOpGreater
|
|
case JumpGreaterOrEqual:
|
|
cond = jumpOpGreaterOrEqual
|
|
case JumpNotEqual:
|
|
cond = jumpOpNotEqual
|
|
case JumpSignedGreater:
|
|
cond = jumpOpSignedGreater
|
|
case JumpSignedGreaterOrEqual:
|
|
cond = jumpOpSignedGreaterOrEqual
|
|
case JumpLess:
|
|
cond = jumpOpLess
|
|
case JumpLessOrEqual:
|
|
cond = jumpOpLessOrEqual
|
|
case JumpSignedLess:
|
|
cond = jumpOpSignedLess
|
|
case JumpSignedLessOrEqual:
|
|
cond = jumpOpSignedLessOrEqual
|
|
default:
|
|
return RawInstruction{}, fmt.Errorf("ebpf: unknown JumpTest %v", test)
|
|
}
|
|
|
|
if immediate {
|
|
return RawInstruction{
|
|
Op: opClassJump | cond | jumpSourceImmediate,
|
|
Dst: dst,
|
|
Offset: int16(offset),
|
|
Immediate: uint64(value),
|
|
}, nil
|
|
}
|
|
return RawInstruction{
|
|
Op: opClassJump | cond | jumpSourceX,
|
|
Dst: dst,
|
|
Src: Register(value & 0x0f),
|
|
Offset: int16(offset),
|
|
}, nil
|
|
}
|
|
|
|
// Exit the eBPF program and return the value of R0.
|
|
type Exit struct{}
|
|
|
|
func (a Exit) Assemble() (RawInstruction, error) {
|
|
return RawInstruction{
|
|
Op: opClassJump | jumpOpExit,
|
|
}, nil
|
|
}
|
|
|
|
func (Exit) String() string {
|
|
return "exit"
|
|
}
|
|
|
|
var (
|
|
_ Instruction = (*Jump)(nil)
|
|
_ Instruction = (*Exit)(nil)
|
|
)
|