Skip to content

Commit 0ab64c5

Browse files
bremlcixtor
authored andcommitted
bpf: implement fmt.Stringer for BPF instructions
Fixes golang/go#18538 Change-Id: Ic0627352f96ad5fa138633d1e1ccfaf76294d621 Reviewed-on: https://go-review.googlesource.com/35171 Run-TryBot: Matt Layher <mdlayher@gmail.com> Reviewed-by: Matt Layher <mdlayher@gmail.com> Reviewed-by: David Anderson <dave@natulte.net> Reviewed-by: Mikio Hara <mikioh.mikioh@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
1 parent c427ad7 commit 0ab64c5

File tree

2 files changed

+594
-0
lines changed

2 files changed

+594
-0
lines changed

bpf/instructions.go

+243
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,18 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
198198
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
199199
}
200200

201+
// String returns the the instruction in assembler notation.
202+
func (a LoadConstant) String() string {
203+
switch a.Dst {
204+
case RegA:
205+
return fmt.Sprintf("ld #%d", a.Val)
206+
case RegX:
207+
return fmt.Sprintf("ldx #%d", a.Val)
208+
default:
209+
return fmt.Sprintf("unknown instruction: %#v", a)
210+
}
211+
}
212+
201213
// LoadScratch loads scratch[N] into register Dst.
202214
type LoadScratch struct {
203215
Dst Register
@@ -212,6 +224,18 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
212224
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
213225
}
214226

227+
// String returns the the instruction in assembler notation.
228+
func (a LoadScratch) String() string {
229+
switch a.Dst {
230+
case RegA:
231+
return fmt.Sprintf("ld M[%d]", a.N)
232+
case RegX:
233+
return fmt.Sprintf("ldx M[%d]", a.N)
234+
default:
235+
return fmt.Sprintf("unknown instruction: %#v", a)
236+
}
237+
}
238+
215239
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
216240
// register A.
217241
type LoadAbsolute struct {
@@ -224,6 +248,23 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
224248
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
225249
}
226250

251+
// String returns the the instruction in assembler notation.
252+
func (a LoadAbsolute) String() string {
253+
switch a.Size {
254+
case 1: // byte
255+
return fmt.Sprintf("ldb [%d]", a.Off)
256+
case 2: // half word
257+
return fmt.Sprintf("ldh [%d]", a.Off)
258+
case 4: // word
259+
if a.Off > extOffset+0xffffffff {
260+
return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
261+
}
262+
return fmt.Sprintf("ld [%d]", a.Off)
263+
default:
264+
return fmt.Sprintf("unknown instruction: %#v", a)
265+
}
266+
}
267+
227268
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
228269
// into register A.
229270
type LoadIndirect struct {
@@ -236,6 +277,20 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
236277
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
237278
}
238279

280+
// String returns the the instruction in assembler notation.
281+
func (a LoadIndirect) String() string {
282+
switch a.Size {
283+
case 1: // byte
284+
return fmt.Sprintf("ldb [x + %d]", a.Off)
285+
case 2: // half word
286+
return fmt.Sprintf("ldh [x + %d]", a.Off)
287+
case 4: // word
288+
return fmt.Sprintf("ld [x + %d]", a.Off)
289+
default:
290+
return fmt.Sprintf("unknown instruction: %#v", a)
291+
}
292+
}
293+
239294
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
240295
// by 4 and stores the result in register X.
241296
//
@@ -251,6 +306,11 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
251306
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
252307
}
253308

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)
312+
}
313+
254314
// LoadExtension invokes a linux-specific extension and stores the
255315
// result in register A.
256316
type LoadExtension struct {
@@ -265,6 +325,46 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
265325
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
266326
}
267327

328+
// String returns the the instruction in assembler notation.
329+
func (a LoadExtension) String() string {
330+
switch a.Num {
331+
case ExtLen:
332+
return "ld #len"
333+
case ExtProto:
334+
return "ld #proto"
335+
case ExtType:
336+
return "ld #type"
337+
case ExtPayloadOffset:
338+
return "ld #poff"
339+
case ExtInterfaceIndex:
340+
return "ld #ifidx"
341+
case ExtNetlinkAttr:
342+
return "ld #nla"
343+
case ExtNetlinkAttrNested:
344+
return "ld #nlan"
345+
case ExtMark:
346+
return "ld #mark"
347+
case ExtQueue:
348+
return "ld #queue"
349+
case ExtLinkLayerType:
350+
return "ld #hatype"
351+
case ExtRXHash:
352+
return "ld #rxhash"
353+
case ExtCPUID:
354+
return "ld #cpu"
355+
case ExtVLANTag:
356+
return "ld #vlan_tci"
357+
case ExtVLANTagPresent:
358+
return "ld #vlan_avail"
359+
case ExtVLANProto:
360+
return "ld #vlan_tpid"
361+
case ExtRand:
362+
return "ld #rand"
363+
default:
364+
return fmt.Sprintf("unknown instruction: %#v", a)
365+
}
366+
}
367+
268368
// StoreScratch stores register Src into scratch[N].
269369
type StoreScratch struct {
270370
Src Register
@@ -292,6 +392,18 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
292392
}, nil
293393
}
294394

395+
// String returns the the instruction in assembler notation.
396+
func (a StoreScratch) String() string {
397+
switch a.Src {
398+
case RegA:
399+
return fmt.Sprintf("st M[%d]", a.N)
400+
case RegX:
401+
return fmt.Sprintf("stx M[%d]", a.N)
402+
default:
403+
return fmt.Sprintf("unknown instruction: %#v", a)
404+
}
405+
}
406+
295407
// ALUOpConstant executes A = A <Op> Val.
296408
type ALUOpConstant struct {
297409
Op ALUOp
@@ -306,6 +418,34 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) {
306418
}, nil
307419
}
308420

421+
// String returns the the instruction in assembler notation.
422+
func (a ALUOpConstant) String() string {
423+
switch a.Op {
424+
case ALUOpAdd:
425+
return fmt.Sprintf("add #%d", a.Val)
426+
case ALUOpSub:
427+
return fmt.Sprintf("sub #%d", a.Val)
428+
case ALUOpMul:
429+
return fmt.Sprintf("mul #%d", a.Val)
430+
case ALUOpDiv:
431+
return fmt.Sprintf("div #%d", a.Val)
432+
case ALUOpMod:
433+
return fmt.Sprintf("mod #%d", a.Val)
434+
case ALUOpAnd:
435+
return fmt.Sprintf("and #%d", a.Val)
436+
case ALUOpOr:
437+
return fmt.Sprintf("or #%d", a.Val)
438+
case ALUOpXor:
439+
return fmt.Sprintf("xor #%d", a.Val)
440+
case ALUOpShiftLeft:
441+
return fmt.Sprintf("lsh #%d", a.Val)
442+
case ALUOpShiftRight:
443+
return fmt.Sprintf("rsh #%d", a.Val)
444+
default:
445+
return fmt.Sprintf("unknown instruction: %#v", a)
446+
}
447+
}
448+
309449
// ALUOpX executes A = A <Op> X
310450
type ALUOpX struct {
311451
Op ALUOp
@@ -318,6 +458,34 @@ func (a ALUOpX) Assemble() (RawInstruction, error) {
318458
}, nil
319459
}
320460

461+
// String returns the the instruction in assembler notation.
462+
func (a ALUOpX) String() string {
463+
switch a.Op {
464+
case ALUOpAdd:
465+
return "add x"
466+
case ALUOpSub:
467+
return "sub x"
468+
case ALUOpMul:
469+
return "mul x"
470+
case ALUOpDiv:
471+
return "div x"
472+
case ALUOpMod:
473+
return "mod x"
474+
case ALUOpAnd:
475+
return "and x"
476+
case ALUOpOr:
477+
return "or x"
478+
case ALUOpXor:
479+
return "xor x"
480+
case ALUOpShiftLeft:
481+
return "lsh x"
482+
case ALUOpShiftRight:
483+
return "rsh x"
484+
default:
485+
return fmt.Sprintf("unknown instruction: %#v", a)
486+
}
487+
}
488+
321489
// NegateA executes A = -A.
322490
type NegateA struct{}
323491

@@ -328,6 +496,11 @@ func (a NegateA) Assemble() (RawInstruction, error) {
328496
}, nil
329497
}
330498

499+
// String returns the the instruction in assembler notation.
500+
func (a NegateA) String() string {
501+
return fmt.Sprintf("neg")
502+
}
503+
331504
// Jump skips the following Skip instructions in the program.
332505
type Jump struct {
333506
Skip uint32
@@ -341,6 +514,11 @@ func (a Jump) Assemble() (RawInstruction, error) {
341514
}, nil
342515
}
343516

517+
// String returns the the instruction in assembler notation.
518+
func (a Jump) String() string {
519+
return fmt.Sprintf("ja %d", a.Skip)
520+
}
521+
344522
// JumpIf skips the following Skip instructions in the program if A
345523
// <Cond> Val is true.
346524
type JumpIf struct {
@@ -388,6 +566,51 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
388566
}, nil
389567
}
390568

569+
// String returns the the instruction in assembler notation.
570+
func (a JumpIf) String() string {
571+
switch a.Cond {
572+
// K == A
573+
case JumpEqual:
574+
return conditionalJump(a, "jeq", "jneq")
575+
// K != A
576+
case JumpNotEqual:
577+
return fmt.Sprintf("jneq #%d,%d", a.Val, a.SkipTrue)
578+
// K > A
579+
case JumpGreaterThan:
580+
return conditionalJump(a, "jgt", "jle")
581+
// K < A
582+
case JumpLessThan:
583+
return fmt.Sprintf("jlt #%d,%d", a.Val, a.SkipTrue)
584+
// K >= A
585+
case JumpGreaterOrEqual:
586+
return conditionalJump(a, "jge", "jlt")
587+
// K <= A
588+
case JumpLessOrEqual:
589+
return fmt.Sprintf("jle #%d,%d", a.Val, a.SkipTrue)
590+
// K & A != 0
591+
case JumpBitsSet:
592+
if a.SkipFalse > 0 {
593+
return fmt.Sprintf("jset #%d,%d,%d", a.Val, a.SkipTrue, a.SkipFalse)
594+
}
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
597+
case JumpBitsNotSet:
598+
return JumpIf{Cond: JumpBitsSet, SkipTrue: a.SkipFalse, SkipFalse: a.SkipTrue, Val: a.Val}.String()
599+
default:
600+
return fmt.Sprintf("unknown instruction: %#v", a)
601+
}
602+
}
603+
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)
608+
}
609+
return fmt.Sprintf("%s #%d,%d", positiveJump, inst.Val, inst.SkipTrue)
610+
}
611+
return fmt.Sprintf("%s #%d,%d", negativeJump, inst.Val, inst.SkipFalse)
612+
}
613+
391614
// RetA exits the BPF program, returning the value of register A.
392615
type RetA struct{}
393616

@@ -398,6 +621,11 @@ func (a RetA) Assemble() (RawInstruction, error) {
398621
}, nil
399622
}
400623

624+
// String returns the the instruction in assembler notation.
625+
func (a RetA) String() string {
626+
return fmt.Sprintf("ret a")
627+
}
628+
401629
// RetConstant exits the BPF program, returning a constant value.
402630
type RetConstant struct {
403631
Val uint32
@@ -411,6 +639,11 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
411639
}, nil
412640
}
413641

642+
// String returns the the instruction in assembler notation.
643+
func (a RetConstant) String() string {
644+
return fmt.Sprintf("ret #%d", a.Val)
645+
}
646+
414647
// TXA copies the value of register X to register A.
415648
type TXA struct{}
416649

@@ -421,6 +654,11 @@ func (a TXA) Assemble() (RawInstruction, error) {
421654
}, nil
422655
}
423656

657+
// String returns the the instruction in assembler notation.
658+
func (a TXA) String() string {
659+
return fmt.Sprintf("txa")
660+
}
661+
424662
// TAX copies the value of register A to register X.
425663
type TAX struct{}
426664

@@ -431,6 +669,11 @@ func (a TAX) Assemble() (RawInstruction, error) {
431669
}, nil
432670
}
433671

672+
// String returns the the instruction in assembler notation.
673+
func (a TAX) String() string {
674+
return fmt.Sprintf("tax")
675+
}
676+
434677
func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
435678
var (
436679
cls uint16

0 commit comments

Comments
 (0)