123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- // Copyright 2016 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package bpf
- import "fmt"
- // An Instruction is one instruction executed by the BPF virtual
- // machine.
- type Instruction interface {
- // Assemble assembles the Instruction into a RawInstruction.
- Assemble() (RawInstruction, error)
- }
- // A RawInstruction is a raw BPF virtual machine instruction.
- type RawInstruction struct {
- // Operation to execute.
- Op uint16
- // For conditional jump instructions, the number of instructions
- // to skip if the condition is true/false.
- Jt uint8
- Jf uint8
- // Constant parameter. The meaning depends on the Op.
- K uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
- // Disassemble parses ri into an Instruction and returns it. If ri is
- // not recognized by this package, ri itself is returned.
- func (ri RawInstruction) Disassemble() Instruction {
- switch ri.Op & opMaskCls {
- case opClsLoadA, opClsLoadX:
- reg := Register(ri.Op & opMaskLoadDest)
- sz := 0
- switch ri.Op & opMaskLoadWidth {
- case opLoadWidth4:
- sz = 4
- case opLoadWidth2:
- sz = 2
- case opLoadWidth1:
- sz = 1
- default:
- return ri
- }
- switch ri.Op & opMaskLoadMode {
- case opAddrModeImmediate:
- if sz != 4 {
- return ri
- }
- return LoadConstant{Dst: reg, Val: ri.K}
- case opAddrModeScratch:
- if sz != 4 || ri.K > 15 {
- return ri
- }
- return LoadScratch{Dst: reg, N: int(ri.K)}
- case opAddrModeAbsolute:
- return LoadAbsolute{Size: sz, Off: ri.K}
- case opAddrModeIndirect:
- return LoadIndirect{Size: sz, Off: ri.K}
- case opAddrModePacketLen:
- if sz != 4 {
- return ri
- }
- return LoadExtension{Num: ExtLen}
- case opAddrModeMemShift:
- return LoadMemShift{Off: ri.K}
- default:
- return ri
- }
- case opClsStoreA:
- if ri.Op != opClsStoreA || ri.K > 15 {
- return ri
- }
- return StoreScratch{Src: RegA, N: int(ri.K)}
- case opClsStoreX:
- if ri.Op != opClsStoreX || ri.K > 15 {
- return ri
- }
- return StoreScratch{Src: RegX, N: int(ri.K)}
- case opClsALU:
- switch op := ALUOp(ri.Op & opMaskOperator); op {
- case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
- if ri.Op&opMaskOperandSrc != 0 {
- return ALUOpX{Op: op}
- }
- return ALUOpConstant{Op: op, Val: ri.K}
- case aluOpNeg:
- return NegateA{}
- default:
- return ri
- }
- case opClsJump:
- if ri.Op&opMaskJumpConst != opClsJump {
- return ri
- }
- switch ri.Op & opMaskJumpCond {
- case opJumpAlways:
- return Jump{Skip: ri.K}
- case opJumpEqual:
- return JumpIf{
- Cond: JumpEqual,
- Val: ri.K,
- SkipTrue: ri.Jt,
- SkipFalse: ri.Jf,
- }
- case opJumpGT:
- return JumpIf{
- Cond: JumpGreaterThan,
- Val: ri.K,
- SkipTrue: ri.Jt,
- SkipFalse: ri.Jf,
- }
- case opJumpGE:
- return JumpIf{
- Cond: JumpGreaterOrEqual,
- Val: ri.K,
- SkipTrue: ri.Jt,
- SkipFalse: ri.Jf,
- }
- case opJumpSet:
- return JumpIf{
- Cond: JumpBitsSet,
- Val: ri.K,
- SkipTrue: ri.Jt,
- SkipFalse: ri.Jf,
- }
- default:
- return ri
- }
- case opClsReturn:
- switch ri.Op {
- case opClsReturn | opRetSrcA:
- return RetA{}
- case opClsReturn | opRetSrcConstant:
- return RetConstant{Val: ri.K}
- default:
- return ri
- }
- case opClsMisc:
- switch ri.Op {
- case opClsMisc | opMiscTAX:
- return TAX{}
- case opClsMisc | opMiscTXA:
- return TXA{}
- default:
- return ri
- }
- default:
- panic("unreachable") // switch is exhaustive on the bit pattern
- }
- }
- // LoadConstant loads Val into register Dst.
- type LoadConstant struct {
- Dst Register
- Val uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadConstant) Assemble() (RawInstruction, error) {
- return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
- }
- // LoadScratch loads scratch[N] into register Dst.
- type LoadScratch struct {
- Dst Register
- N int // 0-15
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadScratch) Assemble() (RawInstruction, error) {
- if a.N < 0 || a.N > 15 {
- return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
- }
- return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
- }
- // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
- // register A.
- type LoadAbsolute struct {
- Off uint32
- Size int // 1, 2 or 4
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadAbsolute) Assemble() (RawInstruction, error) {
- return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
- }
- // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
- // into register A.
- type LoadIndirect struct {
- Off uint32
- Size int // 1, 2 or 4
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadIndirect) Assemble() (RawInstruction, error) {
- return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
- }
- // LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
- // by 4 and stores the result in register X.
- //
- // This instruction is mainly useful to load into X the length of an
- // IPv4 packet header in a single instruction, rather than have to do
- // the arithmetic on the header's first byte by hand.
- type LoadMemShift struct {
- Off uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadMemShift) Assemble() (RawInstruction, error) {
- return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
- }
- // LoadExtension invokes a linux-specific extension and stores the
- // result in register A.
- type LoadExtension struct {
- Num Extension
- }
- // Assemble implements the Instruction Assemble method.
- func (a LoadExtension) Assemble() (RawInstruction, error) {
- if a.Num == ExtLen {
- return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
- }
- return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(-0x1000+a.Num))
- }
- // StoreScratch stores register Src into scratch[N].
- type StoreScratch struct {
- Src Register
- N int // 0-15
- }
- // Assemble implements the Instruction Assemble method.
- func (a StoreScratch) Assemble() (RawInstruction, error) {
- if a.N < 0 || a.N > 15 {
- return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
- }
- var op uint16
- switch a.Src {
- case RegA:
- op = opClsStoreA
- case RegX:
- op = opClsStoreX
- default:
- return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
- }
- return RawInstruction{
- Op: op,
- K: uint32(a.N),
- }, nil
- }
- // ALUOpConstant executes A = A <Op> Val.
- type ALUOpConstant struct {
- Op ALUOp
- Val uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (a ALUOpConstant) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsALU | opALUSrcConstant | uint16(a.Op),
- K: a.Val,
- }, nil
- }
- // ALUOpX executes A = A <Op> X
- type ALUOpX struct {
- Op ALUOp
- }
- // Assemble implements the Instruction Assemble method.
- func (a ALUOpX) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsALU | opALUSrcX | uint16(a.Op),
- }, nil
- }
- // NegateA executes A = -A.
- type NegateA struct{}
- // Assemble implements the Instruction Assemble method.
- func (a NegateA) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsALU | uint16(aluOpNeg),
- }, nil
- }
- // Jump skips the following Skip instructions in the program.
- type Jump struct {
- Skip uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (a Jump) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsJump | opJumpAlways,
- K: a.Skip,
- }, nil
- }
- // JumpIf skips the following Skip instructions in the program if A
- // <Cond> Val is true.
- type JumpIf struct {
- Cond JumpTest
- Val uint32
- SkipTrue uint8
- SkipFalse uint8
- }
- // Assemble implements the Instruction Assemble method.
- func (a JumpIf) Assemble() (RawInstruction, error) {
- var (
- cond uint16
- flip bool
- )
- switch a.Cond {
- case JumpEqual:
- cond = opJumpEqual
- case JumpNotEqual:
- cond, flip = opJumpEqual, true
- case JumpGreaterThan:
- cond = opJumpGT
- case JumpLessThan:
- cond, flip = opJumpGE, true
- case JumpGreaterOrEqual:
- cond = opJumpGE
- case JumpLessOrEqual:
- cond, flip = opJumpGT, true
- case JumpBitsSet:
- cond = opJumpSet
- case JumpBitsNotSet:
- cond, flip = opJumpSet, true
- default:
- return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
- }
- jt, jf := a.SkipTrue, a.SkipFalse
- if flip {
- jt, jf = jf, jt
- }
- return RawInstruction{
- Op: opClsJump | cond,
- Jt: jt,
- Jf: jf,
- K: a.Val,
- }, nil
- }
- // RetA exits the BPF program, returning the value of register A.
- type RetA struct{}
- // Assemble implements the Instruction Assemble method.
- func (a RetA) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsReturn | opRetSrcA,
- }, nil
- }
- // RetConstant exits the BPF program, returning a constant value.
- type RetConstant struct {
- Val uint32
- }
- // Assemble implements the Instruction Assemble method.
- func (a RetConstant) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsReturn | opRetSrcConstant,
- K: a.Val,
- }, nil
- }
- // TXA copies the value of register X to register A.
- type TXA struct{}
- // Assemble implements the Instruction Assemble method.
- func (a TXA) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsMisc | opMiscTXA,
- }, nil
- }
- // TAX copies the value of register A to register X.
- type TAX struct{}
- // Assemble implements the Instruction Assemble method.
- func (a TAX) Assemble() (RawInstruction, error) {
- return RawInstruction{
- Op: opClsMisc | opMiscTAX,
- }, nil
- }
- func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
- var (
- cls uint16
- sz uint16
- )
- switch dst {
- case RegA:
- cls = opClsLoadA
- case RegX:
- cls = opClsLoadX
- default:
- return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
- }
- switch loadSize {
- case 1:
- sz = opLoadWidth1
- case 2:
- sz = opLoadWidth2
- case 4:
- sz = opLoadWidth4
- default:
- return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
- }
- return RawInstruction{
- Op: cls | sz | mode,
- K: k,
- }, nil
- }
|