1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
9 // An Instruction is one instruction executed by the BPF virtual
11 type Instruction interface {
12 // Assemble assembles the Instruction into a RawInstruction.
13 Assemble() (RawInstruction, error)
16 // A RawInstruction is a raw BPF virtual machine instruction.
17 type RawInstruction struct {
18 // Operation to execute.
20 // For conditional jump instructions, the number of instructions
21 // to skip if the condition is true/false.
24 // Constant parameter. The meaning depends on the Op.
28 // Assemble implements the Instruction Assemble method.
29 func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
31 // Disassemble parses ri into an Instruction and returns it. If ri is
32 // not recognized by this package, ri itself is returned.
33 func (ri RawInstruction) Disassemble() Instruction {
34 switch ri.Op & opMaskCls {
35 case opClsLoadA, opClsLoadX:
36 reg := Register(ri.Op & opMaskLoadDest)
38 switch ri.Op & opMaskLoadWidth {
48 switch ri.Op & opMaskLoadMode {
49 case opAddrModeImmediate:
53 return LoadConstant{Dst: reg, Val: ri.K}
54 case opAddrModeScratch:
55 if sz != 4 || ri.K > 15 {
58 return LoadScratch{Dst: reg, N: int(ri.K)}
59 case opAddrModeAbsolute:
60 if ri.K > extOffset+0xffffffff {
61 return LoadExtension{Num: Extension(-extOffset + ri.K)}
63 return LoadAbsolute{Size: sz, Off: ri.K}
64 case opAddrModeIndirect:
65 return LoadIndirect{Size: sz, Off: ri.K}
66 case opAddrModePacketLen:
70 return LoadExtension{Num: ExtLen}
71 case opAddrModeMemShift:
72 return LoadMemShift{Off: ri.K}
78 if ri.Op != opClsStoreA || ri.K > 15 {
81 return StoreScratch{Src: RegA, N: int(ri.K)}
84 if ri.Op != opClsStoreX || ri.K > 15 {
87 return StoreScratch{Src: RegX, N: int(ri.K)}
90 switch op := ALUOp(ri.Op & opMaskOperator); op {
91 case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
92 if ri.Op&opMaskOperandSrc != 0 {
95 return ALUOpConstant{Op: op, Val: ri.K}
103 if ri.Op&opMaskJumpConst != opClsJump {
106 switch ri.Op & opMaskJumpCond {
108 return Jump{Skip: ri.K}
127 Cond: JumpLessOrEqual,
134 Cond: JumpGreaterThan,
149 Cond: JumpGreaterOrEqual,
167 case opClsReturn | opRetSrcA:
169 case opClsReturn | opRetSrcConstant:
170 return RetConstant{Val: ri.K}
177 case opClsMisc | opMiscTAX:
179 case opClsMisc | opMiscTXA:
186 panic("unreachable") // switch is exhaustive on the bit pattern
190 // LoadConstant loads Val into register Dst.
191 type LoadConstant struct {
196 // Assemble implements the Instruction Assemble method.
197 func (a LoadConstant) Assemble() (RawInstruction, error) {
198 return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
201 // String returns the the instruction in assembler notation.
202 func (a LoadConstant) String() string {
205 return fmt.Sprintf("ld #%d", a.Val)
207 return fmt.Sprintf("ldx #%d", a.Val)
209 return fmt.Sprintf("unknown instruction: %#v", a)
213 // LoadScratch loads scratch[N] into register Dst.
214 type LoadScratch struct {
219 // Assemble implements the Instruction Assemble method.
220 func (a LoadScratch) Assemble() (RawInstruction, error) {
221 if a.N < 0 || a.N > 15 {
222 return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
224 return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
227 // String returns the the instruction in assembler notation.
228 func (a LoadScratch) String() string {
231 return fmt.Sprintf("ld M[%d]", a.N)
233 return fmt.Sprintf("ldx M[%d]", a.N)
235 return fmt.Sprintf("unknown instruction: %#v", a)
239 // LoadAbsolute loads packet[Off:Off+Size] as an integer value into
241 type LoadAbsolute struct {
243 Size int // 1, 2 or 4
246 // Assemble implements the Instruction Assemble method.
247 func (a LoadAbsolute) Assemble() (RawInstruction, error) {
248 return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
251 // String returns the the instruction in assembler notation.
252 func (a LoadAbsolute) String() string {
255 return fmt.Sprintf("ldb [%d]", a.Off)
257 return fmt.Sprintf("ldh [%d]", a.Off)
259 if a.Off > extOffset+0xffffffff {
260 return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
262 return fmt.Sprintf("ld [%d]", a.Off)
264 return fmt.Sprintf("unknown instruction: %#v", a)
268 // LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
270 type LoadIndirect struct {
272 Size int // 1, 2 or 4
275 // Assemble implements the Instruction Assemble method.
276 func (a LoadIndirect) Assemble() (RawInstruction, error) {
277 return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
280 // String returns the the instruction in assembler notation.
281 func (a LoadIndirect) String() string {
284 return fmt.Sprintf("ldb [x + %d]", a.Off)
286 return fmt.Sprintf("ldh [x + %d]", a.Off)
288 return fmt.Sprintf("ld [x + %d]", a.Off)
290 return fmt.Sprintf("unknown instruction: %#v", a)
294 // LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
295 // by 4 and stores the result in register X.
297 // This instruction is mainly useful to load into X the length of an
298 // IPv4 packet header in a single instruction, rather than have to do
299 // the arithmetic on the header's first byte by hand.
300 type LoadMemShift struct {
304 // Assemble implements the Instruction Assemble method.
305 func (a LoadMemShift) Assemble() (RawInstruction, error) {
306 return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
309 // String returns the the instruction in assembler notation.
310 func (a LoadMemShift) String() string {
311 return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
314 // LoadExtension invokes a linux-specific extension and stores the
315 // result in register A.
316 type LoadExtension struct {
320 // Assemble implements the Instruction Assemble method.
321 func (a LoadExtension) Assemble() (RawInstruction, error) {
323 return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
325 return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
328 // String returns the the instruction in assembler notation.
329 func (a LoadExtension) String() string {
337 case ExtPayloadOffset:
339 case ExtInterfaceIndex:
343 case ExtNetlinkAttrNested:
349 case ExtLinkLayerType:
356 return "ld #vlan_tci"
357 case ExtVLANTagPresent:
358 return "ld #vlan_avail"
360 return "ld #vlan_tpid"
364 return fmt.Sprintf("unknown instruction: %#v", a)
368 // StoreScratch stores register Src into scratch[N].
369 type StoreScratch struct {
374 // Assemble implements the Instruction Assemble method.
375 func (a StoreScratch) Assemble() (RawInstruction, error) {
376 if a.N < 0 || a.N > 15 {
377 return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
386 return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
389 return RawInstruction{
395 // String returns the the instruction in assembler notation.
396 func (a StoreScratch) String() string {
399 return fmt.Sprintf("st M[%d]", a.N)
401 return fmt.Sprintf("stx M[%d]", a.N)
403 return fmt.Sprintf("unknown instruction: %#v", a)
407 // ALUOpConstant executes A = A <Op> Val.
408 type ALUOpConstant struct {
413 // Assemble implements the Instruction Assemble method.
414 func (a ALUOpConstant) Assemble() (RawInstruction, error) {
415 return RawInstruction{
416 Op: opClsALU | opALUSrcConstant | uint16(a.Op),
421 // String returns the the instruction in assembler notation.
422 func (a ALUOpConstant) String() string {
425 return fmt.Sprintf("add #%d", a.Val)
427 return fmt.Sprintf("sub #%d", a.Val)
429 return fmt.Sprintf("mul #%d", a.Val)
431 return fmt.Sprintf("div #%d", a.Val)
433 return fmt.Sprintf("mod #%d", a.Val)
435 return fmt.Sprintf("and #%d", a.Val)
437 return fmt.Sprintf("or #%d", a.Val)
439 return fmt.Sprintf("xor #%d", a.Val)
441 return fmt.Sprintf("lsh #%d", a.Val)
442 case ALUOpShiftRight:
443 return fmt.Sprintf("rsh #%d", a.Val)
445 return fmt.Sprintf("unknown instruction: %#v", a)
449 // ALUOpX executes A = A <Op> X
454 // Assemble implements the Instruction Assemble method.
455 func (a ALUOpX) Assemble() (RawInstruction, error) {
456 return RawInstruction{
457 Op: opClsALU | opALUSrcX | uint16(a.Op),
461 // String returns the the instruction in assembler notation.
462 func (a ALUOpX) String() string {
482 case ALUOpShiftRight:
485 return fmt.Sprintf("unknown instruction: %#v", a)
489 // NegateA executes A = -A.
490 type NegateA struct{}
492 // Assemble implements the Instruction Assemble method.
493 func (a NegateA) Assemble() (RawInstruction, error) {
494 return RawInstruction{
495 Op: opClsALU | uint16(aluOpNeg),
499 // String returns the the instruction in assembler notation.
500 func (a NegateA) String() string {
501 return fmt.Sprintf("neg")
504 // Jump skips the following Skip instructions in the program.
509 // Assemble implements the Instruction Assemble method.
510 func (a Jump) Assemble() (RawInstruction, error) {
511 return RawInstruction{
512 Op: opClsJump | opJumpAlways,
517 // String returns the the instruction in assembler notation.
518 func (a Jump) String() string {
519 return fmt.Sprintf("ja %d", a.Skip)
522 // JumpIf skips the following Skip instructions in the program if A
523 // <Cond> Val is true.
531 // Assemble implements the Instruction Assemble method.
532 func (a JumpIf) Assemble() (RawInstruction, error) {
541 cond, flip = opJumpEqual, true
542 case JumpGreaterThan:
545 cond, flip = opJumpGE, true
546 case JumpGreaterOrEqual:
548 case JumpLessOrEqual:
549 cond, flip = opJumpGT, true
553 cond, flip = opJumpSet, true
555 return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", a.Cond)
557 jt, jf := a.SkipTrue, a.SkipFalse
561 return RawInstruction{
562 Op: opClsJump | cond,
569 // String returns the the instruction in assembler notation.
570 func (a JumpIf) String() string {
574 return conditionalJump(a, "jeq", "jneq")
577 return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
579 case JumpGreaterThan:
580 return conditionalJump(a, "jgt", "jle")
583 return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
585 case JumpGreaterOrEqual:
586 return conditionalJump(a, "jge", "jlt")
588 case JumpLessOrEqual:
589 return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
593 return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
595 return fmt.Sprintf("jset #%d,%d", a.Val, a.SkipTrue)
596 // K & A == 0, there is no assembler instruction for JumpBitNotSet, use JumpBitSet and invert skips
598 return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
600 return fmt.Sprintf("unknown instruction: %#v", a)
604 func conditionalJump(inst JumpIf, positiveJump, negativeJump string) string {
605 if inst.SkipTrue > 0 {
606 if inst.SkipFalse > 0 {
607 return fmt.Sprintf("%s #%d,%d,%d", positiveJump, inst.Val, inst.SkipTrue, inst.SkipFalse)
609 return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
611 return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
614 // RetA exits the BPF program, returning the value of register A.
617 // Assemble implements the Instruction Assemble method.
618 func (a RetA) Assemble() (RawInstruction, error) {
619 return RawInstruction{
620 Op: opClsReturn | opRetSrcA,
624 // String returns the the instruction in assembler notation.
625 func (a RetA) String() string {
626 return fmt.Sprintf("ret a")
629 // RetConstant exits the BPF program, returning a constant value.
630 type RetConstant struct {
634 // Assemble implements the Instruction Assemble method.
635 func (a RetConstant) Assemble() (RawInstruction, error) {
636 return RawInstruction{
637 Op: opClsReturn | opRetSrcConstant,
642 // String returns the the instruction in assembler notation.
643 func (a RetConstant) String() string {
644 return fmt.Sprintf("ret #%d", a.Val)
647 // TXA copies the value of register X to register A.
650 // Assemble implements the Instruction Assemble method.
651 func (a TXA) Assemble() (RawInstruction, error) {
652 return RawInstruction{
653 Op: opClsMisc | opMiscTXA,
657 // String returns the the instruction in assembler notation.
658 func (a TXA) String() string {
659 return fmt.Sprintf("txa")
662 // TAX copies the value of register A to register X.
665 // Assemble implements the Instruction Assemble method.
666 func (a TAX) Assemble() (RawInstruction, error) {
667 return RawInstruction{
668 Op: opClsMisc | opMiscTAX,
672 // String returns the the instruction in assembler notation.
673 func (a TAX) String() string {
674 return fmt.Sprintf("tax")
677 func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
688 return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
698 return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
700 return RawInstruction{