1
2
3
4
5 package bpf
6
7 import "fmt"
8
9
10
11 type Instruction interface {
12
13 Assemble() (RawInstruction, error)
14 }
15
16
17 type RawInstruction struct {
18
19 Op uint16
20
21
22 Jt uint8
23 Jf uint8
24
25 K uint32
26 }
27
28
29 func (ri RawInstruction) Assemble() (RawInstruction, error) { return ri, nil }
30
31
32
33 func (ri RawInstruction) Disassemble() Instruction {
34 switch ri.Op & opMaskCls {
35 case opClsLoadA, opClsLoadX:
36 reg := Register(ri.Op & opMaskLoadDest)
37 sz := 0
38 switch ri.Op & opMaskLoadWidth {
39 case opLoadWidth4:
40 sz = 4
41 case opLoadWidth2:
42 sz = 2
43 case opLoadWidth1:
44 sz = 1
45 default:
46 return ri
47 }
48 switch ri.Op & opMaskLoadMode {
49 case opAddrModeImmediate:
50 if sz != 4 {
51 return ri
52 }
53 return LoadConstant{Dst: reg, Val: ri.K}
54 case opAddrModeScratch:
55 if sz != 4 || ri.K > 15 {
56 return ri
57 }
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)}
62 }
63 return LoadAbsolute{Size: sz, Off: ri.K}
64 case opAddrModeIndirect:
65 return LoadIndirect{Size: sz, Off: ri.K}
66 case opAddrModePacketLen:
67 if sz != 4 {
68 return ri
69 }
70 return LoadExtension{Num: ExtLen}
71 case opAddrModeMemShift:
72 return LoadMemShift{Off: ri.K}
73 default:
74 return ri
75 }
76
77 case opClsStoreA:
78 if ri.Op != opClsStoreA || ri.K > 15 {
79 return ri
80 }
81 return StoreScratch{Src: RegA, N: int(ri.K)}
82
83 case opClsStoreX:
84 if ri.Op != opClsStoreX || ri.K > 15 {
85 return ri
86 }
87 return StoreScratch{Src: RegX, N: int(ri.K)}
88
89 case opClsALU:
90 switch op := ALUOp(ri.Op & opMaskOperator); op {
91 case ALUOpAdd, ALUOpSub, ALUOpMul, ALUOpDiv, ALUOpOr, ALUOpAnd, ALUOpShiftLeft, ALUOpShiftRight, ALUOpMod, ALUOpXor:
92 switch operand := opOperand(ri.Op & opMaskOperand); operand {
93 case opOperandX:
94 return ALUOpX{Op: op}
95 case opOperandConstant:
96 return ALUOpConstant{Op: op, Val: ri.K}
97 default:
98 return ri
99 }
100 case aluOpNeg:
101 return NegateA{}
102 default:
103 return ri
104 }
105
106 case opClsJump:
107 switch op := jumpOp(ri.Op & opMaskOperator); op {
108 case opJumpAlways:
109 return Jump{Skip: ri.K}
110 case opJumpEqual, opJumpGT, opJumpGE, opJumpSet:
111 cond, skipTrue, skipFalse := jumpOpToTest(op, ri.Jt, ri.Jf)
112 switch operand := opOperand(ri.Op & opMaskOperand); operand {
113 case opOperandX:
114 return JumpIfX{Cond: cond, SkipTrue: skipTrue, SkipFalse: skipFalse}
115 case opOperandConstant:
116 return JumpIf{Cond: cond, Val: ri.K, SkipTrue: skipTrue, SkipFalse: skipFalse}
117 default:
118 return ri
119 }
120 default:
121 return ri
122 }
123
124 case opClsReturn:
125 switch ri.Op {
126 case opClsReturn | opRetSrcA:
127 return RetA{}
128 case opClsReturn | opRetSrcConstant:
129 return RetConstant{Val: ri.K}
130 default:
131 return ri
132 }
133
134 case opClsMisc:
135 switch ri.Op {
136 case opClsMisc | opMiscTAX:
137 return TAX{}
138 case opClsMisc | opMiscTXA:
139 return TXA{}
140 default:
141 return ri
142 }
143
144 default:
145 panic("unreachable")
146 }
147 }
148
149 func jumpOpToTest(op jumpOp, skipTrue uint8, skipFalse uint8) (JumpTest, uint8, uint8) {
150 var test JumpTest
151
152
153
154
155 if skipTrue == 0 {
156 switch op {
157 case opJumpEqual:
158 test = JumpNotEqual
159 case opJumpGT:
160 test = JumpLessOrEqual
161 case opJumpGE:
162 test = JumpLessThan
163 case opJumpSet:
164 test = JumpBitsNotSet
165 }
166
167 return test, skipFalse, 0
168 }
169
170 switch op {
171 case opJumpEqual:
172 test = JumpEqual
173 case opJumpGT:
174 test = JumpGreaterThan
175 case opJumpGE:
176 test = JumpGreaterOrEqual
177 case opJumpSet:
178 test = JumpBitsSet
179 }
180
181 return test, skipTrue, skipFalse
182 }
183
184
185 type LoadConstant struct {
186 Dst Register
187 Val uint32
188 }
189
190
191 func (a LoadConstant) Assemble() (RawInstruction, error) {
192 return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
193 }
194
195
196 func (a LoadConstant) String() string {
197 switch a.Dst {
198 case RegA:
199 return fmt.Sprintf("ld #%d", a.Val)
200 case RegX:
201 return fmt.Sprintf("ldx #%d", a.Val)
202 default:
203 return fmt.Sprintf("unknown instruction: %#v", a)
204 }
205 }
206
207
208 type LoadScratch struct {
209 Dst Register
210 N int
211 }
212
213
214 func (a LoadScratch) Assemble() (RawInstruction, error) {
215 if a.N < 0 || a.N > 15 {
216 return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
217 }
218 return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
219 }
220
221
222 func (a LoadScratch) String() string {
223 switch a.Dst {
224 case RegA:
225 return fmt.Sprintf("ld M[%d]", a.N)
226 case RegX:
227 return fmt.Sprintf("ldx M[%d]", a.N)
228 default:
229 return fmt.Sprintf("unknown instruction: %#v", a)
230 }
231 }
232
233
234
235 type LoadAbsolute struct {
236 Off uint32
237 Size int
238 }
239
240
241 func (a LoadAbsolute) Assemble() (RawInstruction, error) {
242 return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
243 }
244
245
246 func (a LoadAbsolute) String() string {
247 switch a.Size {
248 case 1:
249 return fmt.Sprintf("ldb [%d]", a.Off)
250 case 2:
251 return fmt.Sprintf("ldh [%d]", a.Off)
252 case 4:
253 if a.Off > extOffset+0xffffffff {
254 return LoadExtension{Num: Extension(a.Off + 0x1000)}.String()
255 }
256 return fmt.Sprintf("ld [%d]", a.Off)
257 default:
258 return fmt.Sprintf("unknown instruction: %#v", a)
259 }
260 }
261
262
263
264 type LoadIndirect struct {
265 Off uint32
266 Size int
267 }
268
269
270 func (a LoadIndirect) Assemble() (RawInstruction, error) {
271 return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
272 }
273
274
275 func (a LoadIndirect) String() string {
276 switch a.Size {
277 case 1:
278 return fmt.Sprintf("ldb [x + %d]", a.Off)
279 case 2:
280 return fmt.Sprintf("ldh [x + %d]", a.Off)
281 case 4:
282 return fmt.Sprintf("ld [x + %d]", a.Off)
283 default:
284 return fmt.Sprintf("unknown instruction: %#v", a)
285 }
286 }
287
288
289
290
291
292
293
294 type LoadMemShift struct {
295 Off uint32
296 }
297
298
299 func (a LoadMemShift) Assemble() (RawInstruction, error) {
300 return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
301 }
302
303
304 func (a LoadMemShift) String() string {
305 return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
306 }
307
308
309
310 type LoadExtension struct {
311 Num Extension
312 }
313
314
315 func (a LoadExtension) Assemble() (RawInstruction, error) {
316 if a.Num == ExtLen {
317 return assembleLoad(RegA, 4, opAddrModePacketLen, 0)
318 }
319 return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
320 }
321
322
323 func (a LoadExtension) String() string {
324 switch a.Num {
325 case ExtLen:
326 return "ld #len"
327 case ExtProto:
328 return "ld #proto"
329 case ExtType:
330 return "ld #type"
331 case ExtPayloadOffset:
332 return "ld #poff"
333 case ExtInterfaceIndex:
334 return "ld #ifidx"
335 case ExtNetlinkAttr:
336 return "ld #nla"
337 case ExtNetlinkAttrNested:
338 return "ld #nlan"
339 case ExtMark:
340 return "ld #mark"
341 case ExtQueue:
342 return "ld #queue"
343 case ExtLinkLayerType:
344 return "ld #hatype"
345 case ExtRXHash:
346 return "ld #rxhash"
347 case ExtCPUID:
348 return "ld #cpu"
349 case ExtVLANTag:
350 return "ld #vlan_tci"
351 case ExtVLANTagPresent:
352 return "ld #vlan_avail"
353 case ExtVLANProto:
354 return "ld #vlan_tpid"
355 case ExtRand:
356 return "ld #rand"
357 default:
358 return fmt.Sprintf("unknown instruction: %#v", a)
359 }
360 }
361
362
363 type StoreScratch struct {
364 Src Register
365 N int
366 }
367
368
369 func (a StoreScratch) Assemble() (RawInstruction, error) {
370 if a.N < 0 || a.N > 15 {
371 return RawInstruction{}, fmt.Errorf("invalid scratch slot %d", a.N)
372 }
373 var op uint16
374 switch a.Src {
375 case RegA:
376 op = opClsStoreA
377 case RegX:
378 op = opClsStoreX
379 default:
380 return RawInstruction{}, fmt.Errorf("invalid source register %v", a.Src)
381 }
382
383 return RawInstruction{
384 Op: op,
385 K: uint32(a.N),
386 }, nil
387 }
388
389
390 func (a StoreScratch) String() string {
391 switch a.Src {
392 case RegA:
393 return fmt.Sprintf("st M[%d]", a.N)
394 case RegX:
395 return fmt.Sprintf("stx M[%d]", a.N)
396 default:
397 return fmt.Sprintf("unknown instruction: %#v", a)
398 }
399 }
400
401
402 type ALUOpConstant struct {
403 Op ALUOp
404 Val uint32
405 }
406
407
408 func (a ALUOpConstant) Assemble() (RawInstruction, error) {
409 return RawInstruction{
410 Op: opClsALU | uint16(opOperandConstant) | uint16(a.Op),
411 K: a.Val,
412 }, nil
413 }
414
415
416 func (a ALUOpConstant) String() string {
417 switch a.Op {
418 case ALUOpAdd:
419 return fmt.Sprintf("add #%d", a.Val)
420 case ALUOpSub:
421 return fmt.Sprintf("sub #%d", a.Val)
422 case ALUOpMul:
423 return fmt.Sprintf("mul #%d", a.Val)
424 case ALUOpDiv:
425 return fmt.Sprintf("div #%d", a.Val)
426 case ALUOpMod:
427 return fmt.Sprintf("mod #%d", a.Val)
428 case ALUOpAnd:
429 return fmt.Sprintf("and #%d", a.Val)
430 case ALUOpOr:
431 return fmt.Sprintf("or #%d", a.Val)
432 case ALUOpXor:
433 return fmt.Sprintf("xor #%d", a.Val)
434 case ALUOpShiftLeft:
435 return fmt.Sprintf("lsh #%d", a.Val)
436 case ALUOpShiftRight:
437 return fmt.Sprintf("rsh #%d", a.Val)
438 default:
439 return fmt.Sprintf("unknown instruction: %#v", a)
440 }
441 }
442
443
444 type ALUOpX struct {
445 Op ALUOp
446 }
447
448
449 func (a ALUOpX) Assemble() (RawInstruction, error) {
450 return RawInstruction{
451 Op: opClsALU | uint16(opOperandX) | uint16(a.Op),
452 }, nil
453 }
454
455
456 func (a ALUOpX) String() string {
457 switch a.Op {
458 case ALUOpAdd:
459 return "add x"
460 case ALUOpSub:
461 return "sub x"
462 case ALUOpMul:
463 return "mul x"
464 case ALUOpDiv:
465 return "div x"
466 case ALUOpMod:
467 return "mod x"
468 case ALUOpAnd:
469 return "and x"
470 case ALUOpOr:
471 return "or x"
472 case ALUOpXor:
473 return "xor x"
474 case ALUOpShiftLeft:
475 return "lsh x"
476 case ALUOpShiftRight:
477 return "rsh x"
478 default:
479 return fmt.Sprintf("unknown instruction: %#v", a)
480 }
481 }
482
483
484 type NegateA struct{}
485
486
487 func (a NegateA) Assemble() (RawInstruction, error) {
488 return RawInstruction{
489 Op: opClsALU | uint16(aluOpNeg),
490 }, nil
491 }
492
493
494 func (a NegateA) String() string {
495 return fmt.Sprintf("neg")
496 }
497
498
499 type Jump struct {
500 Skip uint32
501 }
502
503
504 func (a Jump) Assemble() (RawInstruction, error) {
505 return RawInstruction{
506 Op: opClsJump | uint16(opJumpAlways),
507 K: a.Skip,
508 }, nil
509 }
510
511
512 func (a Jump) String() string {
513 return fmt.Sprintf("ja %d", a.Skip)
514 }
515
516
517
518 type JumpIf struct {
519 Cond JumpTest
520 Val uint32
521 SkipTrue uint8
522 SkipFalse uint8
523 }
524
525
526 func (a JumpIf) Assemble() (RawInstruction, error) {
527 return jumpToRaw(a.Cond, opOperandConstant, a.Val, a.SkipTrue, a.SkipFalse)
528 }
529
530
531 func (a JumpIf) String() string {
532 return jumpToString(a.Cond, fmt.Sprintf("#%d", a.Val), a.SkipTrue, a.SkipFalse)
533 }
534
535
536
537 type JumpIfX struct {
538 Cond JumpTest
539 SkipTrue uint8
540 SkipFalse uint8
541 }
542
543
544 func (a JumpIfX) Assemble() (RawInstruction, error) {
545 return jumpToRaw(a.Cond, opOperandX, 0, a.SkipTrue, a.SkipFalse)
546 }
547
548
549 func (a JumpIfX) String() string {
550 return jumpToString(a.Cond, "x", a.SkipTrue, a.SkipFalse)
551 }
552
553
554 func jumpToRaw(test JumpTest, operand opOperand, k uint32, skipTrue, skipFalse uint8) (RawInstruction, error) {
555 var (
556 cond jumpOp
557 flip bool
558 )
559 switch test {
560 case JumpEqual:
561 cond = opJumpEqual
562 case JumpNotEqual:
563 cond, flip = opJumpEqual, true
564 case JumpGreaterThan:
565 cond = opJumpGT
566 case JumpLessThan:
567 cond, flip = opJumpGE, true
568 case JumpGreaterOrEqual:
569 cond = opJumpGE
570 case JumpLessOrEqual:
571 cond, flip = opJumpGT, true
572 case JumpBitsSet:
573 cond = opJumpSet
574 case JumpBitsNotSet:
575 cond, flip = opJumpSet, true
576 default:
577 return RawInstruction{}, fmt.Errorf("unknown JumpTest %v", test)
578 }
579 jt, jf := skipTrue, skipFalse
580 if flip {
581 jt, jf = jf, jt
582 }
583 return RawInstruction{
584 Op: opClsJump | uint16(cond) | uint16(operand),
585 Jt: jt,
586 Jf: jf,
587 K: k,
588 }, nil
589 }
590
591
592 func jumpToString(cond JumpTest, operand string, skipTrue, skipFalse uint8) string {
593 switch cond {
594
595 case JumpEqual:
596 return conditionalJump(operand, skipTrue, skipFalse, "jeq", "jneq")
597
598 case JumpNotEqual:
599 return fmt.Sprintf("jneq %s,%d", operand, skipTrue)
600
601 case JumpGreaterThan:
602 return conditionalJump(operand, skipTrue, skipFalse, "jgt", "jle")
603
604 case JumpLessThan:
605 return fmt.Sprintf("jlt %s,%d", operand, skipTrue)
606
607 case JumpGreaterOrEqual:
608 return conditionalJump(operand, skipTrue, skipFalse, "jge", "jlt")
609
610 case JumpLessOrEqual:
611 return fmt.Sprintf("jle %s,%d", operand, skipTrue)
612
613 case JumpBitsSet:
614 if skipFalse > 0 {
615 return fmt.Sprintf("jset %s,%d,%d", operand, skipTrue, skipFalse)
616 }
617 return fmt.Sprintf("jset %s,%d", operand, skipTrue)
618
619 case JumpBitsNotSet:
620 return jumpToString(JumpBitsSet, operand, skipFalse, skipTrue)
621 default:
622 return fmt.Sprintf("unknown JumpTest %#v", cond)
623 }
624 }
625
626 func conditionalJump(operand string, skipTrue, skipFalse uint8, positiveJump, negativeJump string) string {
627 if skipTrue > 0 {
628 if skipFalse > 0 {
629 return fmt.Sprintf("%s %s,%d,%d", positiveJump, operand, skipTrue, skipFalse)
630 }
631 return fmt.Sprintf("%s %s,%d", positiveJump, operand, skipTrue)
632 }
633 return fmt.Sprintf("%s %s,%d", negativeJump, operand, skipFalse)
634 }
635
636
637 type RetA struct{}
638
639
640 func (a RetA) Assemble() (RawInstruction, error) {
641 return RawInstruction{
642 Op: opClsReturn | opRetSrcA,
643 }, nil
644 }
645
646
647 func (a RetA) String() string {
648 return fmt.Sprintf("ret a")
649 }
650
651
652 type RetConstant struct {
653 Val uint32
654 }
655
656
657 func (a RetConstant) Assemble() (RawInstruction, error) {
658 return RawInstruction{
659 Op: opClsReturn | opRetSrcConstant,
660 K: a.Val,
661 }, nil
662 }
663
664
665 func (a RetConstant) String() string {
666 return fmt.Sprintf("ret #%d", a.Val)
667 }
668
669
670 type TXA struct{}
671
672
673 func (a TXA) Assemble() (RawInstruction, error) {
674 return RawInstruction{
675 Op: opClsMisc | opMiscTXA,
676 }, nil
677 }
678
679
680 func (a TXA) String() string {
681 return fmt.Sprintf("txa")
682 }
683
684
685 type TAX struct{}
686
687
688 func (a TAX) Assemble() (RawInstruction, error) {
689 return RawInstruction{
690 Op: opClsMisc | opMiscTAX,
691 }, nil
692 }
693
694
695 func (a TAX) String() string {
696 return fmt.Sprintf("tax")
697 }
698
699 func assembleLoad(dst Register, loadSize int, mode uint16, k uint32) (RawInstruction, error) {
700 var (
701 cls uint16
702 sz uint16
703 )
704 switch dst {
705 case RegA:
706 cls = opClsLoadA
707 case RegX:
708 cls = opClsLoadX
709 default:
710 return RawInstruction{}, fmt.Errorf("invalid target register %v", dst)
711 }
712 switch loadSize {
713 case 1:
714 sz = opLoadWidth1
715 case 2:
716 sz = opLoadWidth2
717 case 4:
718 sz = opLoadWidth4
719 default:
720 return RawInstruction{}, fmt.Errorf("invalid load byte length %d", sz)
721 }
722 return RawInstruction{
723 Op: cls | sz | mode,
724 K: k,
725 }, nil
726 }
727
View as plain text