@@ -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.
202214type 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.
217241type 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.
229270type 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.
256316type 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].
269369type 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.
296408type 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
310450type 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.
322490type 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.
332505type 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.
346524type 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.
392615type 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.
402630type 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.
415648type 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.
425663type 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+
434677func assembleLoad (dst Register , loadSize int , mode uint16 , k uint32 ) (RawInstruction , error ) {
435678 var (
436679 cls uint16
0 commit comments