@@ -198,6 +198,18 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
198
198
return assembleLoad (a .Dst , 4 , opAddrModeImmediate , a .Val )
199
199
}
200
200
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
+
201
213
// LoadScratch loads scratch[N] into register Dst.
202
214
type LoadScratch struct {
203
215
Dst Register
@@ -212,6 +224,18 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
212
224
return assembleLoad (a .Dst , 4 , opAddrModeScratch , uint32 (a .N ))
213
225
}
214
226
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
+
215
239
// LoadAbsolute loads packet[Off:Off+Size] as an integer value into
216
240
// register A.
217
241
type LoadAbsolute struct {
@@ -224,6 +248,23 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
224
248
return assembleLoad (RegA , a .Size , opAddrModeAbsolute , a .Off )
225
249
}
226
250
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
+
227
268
// LoadIndirect loads packet[X+Off:X+Off+Size] as an integer value
228
269
// into register A.
229
270
type LoadIndirect struct {
@@ -236,6 +277,20 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
236
277
return assembleLoad (RegA , a .Size , opAddrModeIndirect , a .Off )
237
278
}
238
279
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
+
239
294
// LoadMemShift multiplies the first 4 bits of the byte at packet[Off]
240
295
// by 4 and stores the result in register X.
241
296
//
@@ -251,6 +306,11 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
251
306
return assembleLoad (RegX , 1 , opAddrModeMemShift , a .Off )
252
307
}
253
308
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
+
254
314
// LoadExtension invokes a linux-specific extension and stores the
255
315
// result in register A.
256
316
type LoadExtension struct {
@@ -265,6 +325,46 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
265
325
return assembleLoad (RegA , 4 , opAddrModeAbsolute , uint32 (extOffset + a .Num ))
266
326
}
267
327
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
+
268
368
// StoreScratch stores register Src into scratch[N].
269
369
type StoreScratch struct {
270
370
Src Register
@@ -292,6 +392,18 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
292
392
}, nil
293
393
}
294
394
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
+
295
407
// ALUOpConstant executes A = A <Op> Val.
296
408
type ALUOpConstant struct {
297
409
Op ALUOp
@@ -306,6 +418,34 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) {
306
418
}, nil
307
419
}
308
420
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
+
309
449
// ALUOpX executes A = A <Op> X
310
450
type ALUOpX struct {
311
451
Op ALUOp
@@ -318,6 +458,34 @@ func (a ALUOpX) Assemble() (RawInstruction, error) {
318
458
}, nil
319
459
}
320
460
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
+
321
489
// NegateA executes A = -A.
322
490
type NegateA struct {}
323
491
@@ -328,6 +496,11 @@ func (a NegateA) Assemble() (RawInstruction, error) {
328
496
}, nil
329
497
}
330
498
499
+ // String returns the the instruction in assembler notation.
500
+ func (a NegateA ) String () string {
501
+ return fmt .Sprintf ("neg" )
502
+ }
503
+
331
504
// Jump skips the following Skip instructions in the program.
332
505
type Jump struct {
333
506
Skip uint32
@@ -341,6 +514,11 @@ func (a Jump) Assemble() (RawInstruction, error) {
341
514
}, nil
342
515
}
343
516
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
+
344
522
// JumpIf skips the following Skip instructions in the program if A
345
523
// <Cond> Val is true.
346
524
type JumpIf struct {
@@ -388,6 +566,51 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
388
566
}, nil
389
567
}
390
568
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
+
391
614
// RetA exits the BPF program, returning the value of register A.
392
615
type RetA struct {}
393
616
@@ -398,6 +621,11 @@ func (a RetA) Assemble() (RawInstruction, error) {
398
621
}, nil
399
622
}
400
623
624
+ // String returns the the instruction in assembler notation.
625
+ func (a RetA ) String () string {
626
+ return fmt .Sprintf ("ret a" )
627
+ }
628
+
401
629
// RetConstant exits the BPF program, returning a constant value.
402
630
type RetConstant struct {
403
631
Val uint32
@@ -411,6 +639,11 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
411
639
}, nil
412
640
}
413
641
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
+
414
647
// TXA copies the value of register X to register A.
415
648
type TXA struct {}
416
649
@@ -421,6 +654,11 @@ func (a TXA) Assemble() (RawInstruction, error) {
421
654
}, nil
422
655
}
423
656
657
+ // String returns the the instruction in assembler notation.
658
+ func (a TXA ) String () string {
659
+ return fmt .Sprintf ("txa" )
660
+ }
661
+
424
662
// TAX copies the value of register A to register X.
425
663
type TAX struct {}
426
664
@@ -431,6 +669,11 @@ func (a TAX) Assemble() (RawInstruction, error) {
431
669
}, nil
432
670
}
433
671
672
+ // String returns the the instruction in assembler notation.
673
+ func (a TAX ) String () string {
674
+ return fmt .Sprintf ("tax" )
675
+ }
676
+
434
677
func assembleLoad (dst Register , loadSize int , mode uint16 , k uint32 ) (RawInstruction , error ) {
435
678
var (
436
679
cls uint16
0 commit comments