xref: /DragonOS/kernel/crates/rbpf/src/insn_builder.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2 // Copyright 2017 Alex Dukhno <alex.dukhno@icloud.com>
3 
4 //! Module provides API to create eBPF programs by Rust programming language
5 
6 use alloc::{vec, vec::Vec};
7 
8 use crate::ebpf::*;
9 
10 /// Represents single eBPF instruction
11 pub trait Instruction: Sized {
12     /// returns instruction opt code
13     fn opt_code_byte(&self) -> u8;
14 
15     /// returns destination register
16     fn get_dst(&self) -> u8 {
17         self.get_insn().dst
18     }
19 
20     /// returns source register
21     fn get_src(&self) -> u8 {
22         self.get_insn().src
23     }
24 
25     /// returns offset bytes
26     fn get_off(&self) -> i16 {
27         self.get_insn().off
28     }
29 
30     /// returns immediate value
31     fn get_imm(&self) -> i32 {
32         self.get_insn().imm
33     }
34 
35     /// sets destination register
36     fn set_dst(mut self, dst: u8) -> Self {
37         self.get_insn_mut().dst = dst;
38         self
39     }
40 
41     /// sets source register
42     fn set_src(mut self, src: u8) -> Self {
43         self.get_insn_mut().src = src;
44         self
45     }
46 
47     /// sets offset bytes
48     fn set_off(mut self, offset: i16) -> Self {
49         self.get_insn_mut().off = offset;
50         self
51     }
52 
53     /// sets immediate value
54     fn set_imm(mut self, imm: i32) -> Self {
55         self.get_insn_mut().imm = imm;
56         self
57     }
58 
59     /// get `ebpf::Insn` struct
60     fn get_insn(&self) -> &Insn;
61 
62     /// get mutable `ebpf::Insn` struct
63     fn get_insn_mut(&mut self) -> &mut Insn;
64 }
65 
66 /// General trait for `Instruction`s and `BpfCode`.
67 /// Provides functionality to transform `struct` into collection of bytes
68 pub trait IntoBytes {
69     /// type of targeted transformation
70     type Bytes;
71 
72     /// consume `Self` with transformation into `Self::Bytes`
73     fn into_bytes(self) -> Self::Bytes;
74 }
75 
76 /// General implementation of `IntoBytes` for `Instruction`
77 impl<'i, I: Instruction> IntoBytes for &'i I {
78     type Bytes = Vec<u8>;
79 
80     /// transform immutable reference of `Instruction` into `Vec<u8>` with size of 8
81     /// [ 1 byte ,      1 byte      , 2 bytes,  4 bytes  ]
82     /// [ OP_CODE, SRC_REG | DST_REG, OFFSET , IMMEDIATE ]
83     fn into_bytes(self) -> Self::Bytes {
84         let buffer = vec![
85             self.opt_code_byte(),
86             self.get_src() << 4 | self.get_dst(),
87             self.get_off() as u8,
88             (self.get_off() >> 8) as u8,
89             self.get_imm() as u8,
90             (self.get_imm() >> 8) as u8,
91             (self.get_imm() >> 16) as u8,
92             (self.get_imm() >> 24) as u8,
93         ];
94         buffer
95     }
96 }
97 
98 /// BPF instruction stack in byte representation
99 #[derive(Default)]
100 pub struct BpfCode {
101     instructions: Vec<u8>,
102 }
103 
104 impl BpfCode {
105     /// creates new empty BPF instruction stack
106     pub fn new() -> Self {
107         BpfCode {
108             instructions: vec![],
109         }
110     }
111 
112     /// create ADD instruction
113     pub fn add(&mut self, source: Source, arch: Arch) -> Move {
114         self.mov_internal(source, arch, OpBits::Add)
115     }
116 
117     /// create SUB instruction
118     pub fn sub(&mut self, source: Source, arch: Arch) -> Move {
119         self.mov_internal(source, arch, OpBits::Sub)
120     }
121 
122     /// create MUL instruction
123     pub fn mul(&mut self, source: Source, arch: Arch) -> Move {
124         self.mov_internal(source, arch, OpBits::Mul)
125     }
126 
127     /// create DIV instruction
128     pub fn div(&mut self, source: Source, arch: Arch) -> Move {
129         self.mov_internal(source, arch, OpBits::Div)
130     }
131 
132     /// create OR instruction
133     pub fn bit_or(&mut self, source: Source, arch: Arch) -> Move {
134         self.mov_internal(source, arch, OpBits::BitOr)
135     }
136 
137     /// create AND instruction
138     pub fn bit_and(&mut self, source: Source, arch: Arch) -> Move {
139         self.mov_internal(source, arch, OpBits::BitAnd)
140     }
141 
142     /// create LSHIFT instruction
143     pub fn left_shift(&mut self, source: Source, arch: Arch) -> Move {
144         self.mov_internal(source, arch, OpBits::LShift)
145     }
146 
147     /// create RSHIFT instruction
148     pub fn right_shift(&mut self, source: Source, arch: Arch) -> Move {
149         self.mov_internal(source, arch, OpBits::RShift)
150     }
151 
152     /// create NEGATE instruction
153     pub fn negate(&mut self, arch: Arch) -> Move {
154         self.mov_internal(Source::Imm, arch, OpBits::Negate)
155     }
156 
157     /// create MOD instruction
158     pub fn modulo(&mut self, source: Source, arch: Arch) -> Move {
159         self.mov_internal(source, arch, OpBits::Mod)
160     }
161 
162     /// create XOR instruction
163     pub fn bit_xor(&mut self, source: Source, arch: Arch) -> Move {
164         self.mov_internal(source, arch, OpBits::BitXor)
165     }
166 
167     /// create MOV instruction
168     pub fn mov(&mut self, source: Source, arch: Arch) -> Move {
169         self.mov_internal(source, arch, OpBits::Mov)
170     }
171 
172     /// create SIGNED RSHIFT instruction
173     pub fn signed_right_shift(&mut self, source: Source, arch: Arch) -> Move {
174         self.mov_internal(source, arch, OpBits::SignRShift)
175     }
176 
177     #[inline]
178     fn mov_internal(&mut self, source: Source, arch_bits: Arch, op_bits: OpBits) -> Move {
179         Move {
180             bpf_code: self,
181             src_bit: source,
182             op_bits,
183             arch_bits,
184             insn: Insn {
185                 opc: 0x00,
186                 dst: 0x00,
187                 src: 0x00,
188                 off: 0x00_00,
189                 imm: 0x00_00_00_00,
190             },
191         }
192     }
193 
194     /// create byte swap instruction
195     pub fn swap_bytes(&mut self, endian: Endian) -> SwapBytes {
196         SwapBytes {
197             bpf_code: self,
198             endian,
199             insn: Insn {
200                 opc: 0x00,
201                 dst: 0x00,
202                 src: 0x00,
203                 off: 0x00_00,
204                 imm: 0x00_00_00_00,
205             },
206         }
207     }
208 
209     /// create LOAD instruction, IMMEDIATE is the source
210     pub fn load(&mut self, mem_size: MemSize) -> Load {
211         self.load_internal(mem_size, Addressing::Imm, BPF_LD)
212     }
213 
214     /// create ABSOLUTE LOAD instruction
215     pub fn load_abs(&mut self, mem_size: MemSize) -> Load {
216         self.load_internal(mem_size, Addressing::Abs, BPF_LD)
217     }
218 
219     /// create INDIRECT LOAD instruction
220     pub fn load_ind(&mut self, mem_size: MemSize) -> Load {
221         self.load_internal(mem_size, Addressing::Ind, BPF_LD)
222     }
223 
224     /// create LOAD instruction, MEMORY is the source
225     pub fn load_x(&mut self, mem_size: MemSize) -> Load {
226         self.load_internal(mem_size, Addressing::Mem, BPF_LDX)
227     }
228 
229     #[inline]
230     fn load_internal(&mut self, mem_size: MemSize, addressing: Addressing, source: u8) -> Load {
231         Load {
232             bpf_code: self,
233             addressing,
234             mem_size,
235             source,
236             insn: Insn {
237                 opc: 0x00,
238                 dst: 0x00,
239                 src: 0x00,
240                 off: 0x00_00,
241                 imm: 0x00_00_00_00,
242             },
243         }
244     }
245 
246     /// creates STORE instruction, IMMEDIATE is the source
247     pub fn store(&mut self, mem_size: MemSize) -> Store {
248         self.store_internal(mem_size, BPF_IMM)
249     }
250 
251     /// creates STORE instruction, MEMORY is the source
252     pub fn store_x(&mut self, mem_size: MemSize) -> Store {
253         self.store_internal(mem_size, BPF_MEM | BPF_STX)
254     }
255 
256     #[inline]
257     fn store_internal(&mut self, mem_size: MemSize, source: u8) -> Store {
258         Store {
259             bpf_code: self,
260             mem_size,
261             source,
262             insn: Insn {
263                 opc: 0x00,
264                 dst: 0x00,
265                 src: 0x00,
266                 off: 0x00_00,
267                 imm: 0x00_00_00_00,
268             },
269         }
270     }
271 
272     /// create unconditional JMP instruction
273     pub fn jump_unconditional(&mut self) -> Jump {
274         self.jump_conditional(Cond::Abs, Source::Imm)
275     }
276 
277     /// create conditional JMP instruction
278     pub fn jump_conditional(&mut self, cond: Cond, src_bit: Source) -> Jump {
279         Jump {
280             bpf_code: self,
281             cond,
282             src_bit,
283             insn: Insn {
284                 opc: 0x00,
285                 dst: 0x00,
286                 src: 0x00,
287                 off: 0x00_00,
288                 imm: 0x00_00_00_00,
289             },
290         }
291     }
292 
293     /// create CALL instruction
294     pub fn call(&mut self) -> FunctionCall {
295         FunctionCall {
296             bpf_code: self,
297             insn: Insn {
298                 opc: 0x00,
299                 dst: 0x00,
300                 src: 0x00,
301                 off: 0x00_00,
302                 imm: 0x00_00_00_00,
303             },
304         }
305     }
306 
307     /// create EXIT instruction
308     pub fn exit(&mut self) -> Exit {
309         Exit {
310             bpf_code: self,
311             insn: Insn {
312                 opc: 0x00,
313                 dst: 0x00,
314                 src: 0x00,
315                 off: 0x00_00,
316                 imm: 0x00_00_00_00,
317             },
318         }
319     }
320 }
321 
322 /// Transform `BpfCode` into assemble representation
323 impl<'a> IntoBytes for &'a BpfCode {
324     type Bytes = &'a [u8];
325 
326     /// returns `BpfCode` instruction stack as `&[u8]`
327     fn into_bytes(self) -> Self::Bytes {
328         self.instructions.as_slice()
329     }
330 }
331 
332 /// struct to represent `MOV ALU` instructions
333 pub struct Move<'i> {
334     bpf_code: &'i mut BpfCode,
335     src_bit: Source,
336     op_bits: OpBits,
337     arch_bits: Arch,
338     insn: Insn,
339 }
340 
341 impl<'i> Move<'i> {
342     /// push MOV instruction into BpfCode instruction stack
343     pub fn push(self) -> &'i mut BpfCode {
344         let mut asm = self.into_bytes();
345         self.bpf_code.instructions.append(&mut asm);
346         self.bpf_code
347     }
348 }
349 
350 impl<'i> Instruction for Move<'i> {
351     fn opt_code_byte(&self) -> u8 {
352         let op_bits = self.op_bits as u8;
353         let src_bit = self.src_bit as u8;
354         let arch_bits = self.arch_bits as u8;
355         op_bits | src_bit | arch_bits
356     }
357 
358     fn get_insn_mut(&mut self) -> &mut Insn {
359         &mut self.insn
360     }
361 
362     fn get_insn(&self) -> &Insn {
363         &self.insn
364     }
365 }
366 
367 #[derive(Copy, Clone, PartialEq, Eq)]
368 /// The source of ALU and JMP instructions
369 pub enum Source {
370     /// immediate field will be used as a source
371     Imm = BPF_IMM as isize,
372     /// src register will be used as a source
373     Reg = BPF_X as isize,
374 }
375 
376 #[derive(Copy, Clone)]
377 enum OpBits {
378     Add = BPF_ADD as isize,
379     Sub = BPF_SUB as isize,
380     Mul = BPF_MUL as isize,
381     Div = BPF_DIV as isize,
382     BitOr = BPF_OR as isize,
383     BitAnd = BPF_AND as isize,
384     LShift = BPF_LSH as isize,
385     RShift = BPF_RSH as isize,
386     Negate = BPF_NEG as isize,
387     Mod = BPF_MOD as isize,
388     BitXor = BPF_XOR as isize,
389     Mov = BPF_MOV as isize,
390     SignRShift = BPF_ARSH as isize,
391 }
392 
393 #[derive(Copy, Clone)]
394 /// Architecture of instructions
395 pub enum Arch {
396     /// 64-bit instructions
397     X64 = BPF_ALU64 as isize,
398     /// 32-bit instructions
399     X32 = BPF_ALU as isize,
400 }
401 
402 /// struct representation of byte swap operation
403 pub struct SwapBytes<'i> {
404     bpf_code: &'i mut BpfCode,
405     endian: Endian,
406     insn: Insn,
407 }
408 
409 impl<'i> SwapBytes<'i> {
410     /// push bytes swap instruction into BpfCode instruction stack
411     pub fn push(self) -> &'i mut BpfCode {
412         let mut asm = self.into_bytes();
413         self.bpf_code.instructions.append(&mut asm);
414         self.bpf_code
415     }
416 }
417 
418 impl<'i> Instruction for SwapBytes<'i> {
419     fn opt_code_byte(&self) -> u8 {
420         self.endian as u8
421     }
422 
423     fn get_insn_mut(&mut self) -> &mut Insn {
424         &mut self.insn
425     }
426 
427     fn get_insn(&self) -> &Insn {
428         &self.insn
429     }
430 }
431 
432 #[derive(Copy, Clone)]
433 /// Bytes endian
434 pub enum Endian {
435     /// Little endian
436     Little = LE as isize,
437     /// Big endian
438     Big = BE as isize,
439 }
440 
441 /// struct representation of LOAD instructions
442 pub struct Load<'i> {
443     bpf_code: &'i mut BpfCode,
444     addressing: Addressing,
445     mem_size: MemSize,
446     source: u8,
447     insn: Insn,
448 }
449 
450 impl<'i> Load<'i> {
451     /// push LOAD instruction into BpfCode instruction stack
452     pub fn push(self) -> &'i mut BpfCode {
453         let mut asm = self.into_bytes();
454         self.bpf_code.instructions.append(&mut asm);
455         self.bpf_code
456     }
457 }
458 
459 impl<'i> Instruction for Load<'i> {
460     fn opt_code_byte(&self) -> u8 {
461         let size = self.mem_size as u8;
462         let addressing = self.addressing as u8;
463         addressing | size | self.source
464     }
465 
466     fn get_insn_mut(&mut self) -> &mut Insn {
467         &mut self.insn
468     }
469 
470     fn get_insn(&self) -> &Insn {
471         &self.insn
472     }
473 }
474 
475 /// struct representation of STORE instructions
476 pub struct Store<'i> {
477     bpf_code: &'i mut BpfCode,
478     mem_size: MemSize,
479     source: u8,
480     insn: Insn,
481 }
482 
483 impl<'i> Store<'i> {
484     /// push STORE instruction into BpfCode instruction stack
485     pub fn push(self) -> &'i mut BpfCode {
486         let mut asm = self.into_bytes();
487         self.bpf_code.instructions.append(&mut asm);
488         self.bpf_code
489     }
490 }
491 
492 impl<'i> Instruction for Store<'i> {
493     fn opt_code_byte(&self) -> u8 {
494         let size = self.mem_size as u8;
495         BPF_MEM | BPF_ST | size | self.source
496     }
497 
498     fn get_insn_mut(&mut self) -> &mut Insn {
499         &mut self.insn
500     }
501 
502     fn get_insn(&self) -> &Insn {
503         &self.insn
504     }
505 }
506 
507 #[derive(Copy, Clone)]
508 /// Memory size for LOAD and STORE instructions
509 pub enum MemSize {
510     /// 8-bit size
511     Byte = BPF_B as isize,
512     /// 16-bit size
513     HalfWord = BPF_H as isize,
514     /// 32-bit size
515     Word = BPF_W as isize,
516     /// 64-bit size
517     DoubleWord = BPF_DW as isize,
518 }
519 
520 #[derive(Copy, Clone)]
521 enum Addressing {
522     Imm = BPF_IMM as isize,
523     Abs = BPF_ABS as isize,
524     Ind = BPF_IND as isize,
525     Mem = BPF_MEM as isize,
526 }
527 
528 /// struct representation of JMP instructions
529 pub struct Jump<'i> {
530     bpf_code: &'i mut BpfCode,
531     cond: Cond,
532     src_bit: Source,
533     insn: Insn,
534 }
535 
536 impl<'i> Jump<'i> {
537     /// push JMP instruction into BpfCode instruction stack
538     pub fn push(self) -> &'i mut BpfCode {
539         let mut asm = self.into_bytes();
540         self.bpf_code.instructions.append(&mut asm);
541         self.bpf_code
542     }
543 }
544 
545 impl<'i> Instruction for Jump<'i> {
546     fn opt_code_byte(&self) -> u8 {
547         let cmp: u8 = self.cond as u8;
548         let src_bit = self.src_bit as u8;
549         cmp | src_bit | BPF_JMP
550     }
551 
552     fn get_insn_mut(&mut self) -> &mut Insn {
553         &mut self.insn
554     }
555 
556     fn get_insn(&self) -> &Insn {
557         &self.insn
558     }
559 }
560 
561 #[derive(Copy, Clone, PartialEq, Eq)]
562 /// Conditions for JMP instructions
563 pub enum Cond {
564     /// Absolute or unconditional
565     Abs = BPF_JA as isize,
566     /// Jump if `==`
567     Equals = BPF_JEQ as isize,
568     /// Jump if `>`
569     Greater = BPF_JGT as isize,
570     /// Jump if `>=`
571     GreaterEquals = BPF_JGE as isize,
572     /// Jump if `<`
573     Lower = BPF_JLT as isize,
574     /// Jump if `<=`
575     LowerEquals = BPF_JLE as isize,
576     /// Jump if `src` & `dst`
577     BitAnd = BPF_JSET as isize,
578     /// Jump if `!=`
579     NotEquals = BPF_JNE as isize,
580     /// Jump if `>` (signed)
581     GreaterSigned = BPF_JSGT as isize,
582     /// Jump if `>=` (signed)
583     GreaterEqualsSigned = BPF_JSGE as isize,
584     /// Jump if `<` (signed)
585     LowerSigned = BPF_JSLT as isize,
586     /// Jump if `<=` (signed)
587     LowerEqualsSigned = BPF_JSLE as isize,
588 }
589 
590 /// struct representation of CALL instruction
591 pub struct FunctionCall<'i> {
592     bpf_code: &'i mut BpfCode,
593     insn: Insn,
594 }
595 
596 impl<'i> FunctionCall<'i> {
597     /// push CALL instruction into BpfCode instruction stack
598     pub fn push(self) -> &'i mut BpfCode {
599         let mut asm = self.into_bytes();
600         self.bpf_code.instructions.append(&mut asm);
601         self.bpf_code
602     }
603 }
604 
605 impl<'i> Instruction for FunctionCall<'i> {
606     fn opt_code_byte(&self) -> u8 {
607         BPF_CALL | BPF_JMP
608     }
609 
610     fn get_insn_mut(&mut self) -> &mut Insn {
611         &mut self.insn
612     }
613 
614     fn get_insn(&self) -> &Insn {
615         &self.insn
616     }
617 }
618 
619 /// struct representation of EXIT instruction
620 pub struct Exit<'i> {
621     bpf_code: &'i mut BpfCode,
622     insn: Insn,
623 }
624 
625 impl<'i> Exit<'i> {
626     /// push EXIT instruction into BpfCode instruction stack
627     pub fn push(self) -> &'i mut BpfCode {
628         let mut asm = self.into_bytes();
629         self.bpf_code.instructions.append(&mut asm);
630         self.bpf_code
631     }
632 }
633 
634 impl<'i> Instruction for Exit<'i> {
635     fn opt_code_byte(&self) -> u8 {
636         BPF_EXIT | BPF_JMP
637     }
638 
639     fn get_insn_mut(&mut self) -> &mut Insn {
640         &mut self.insn
641     }
642 
643     fn get_insn(&self) -> &Insn {
644         &self.insn
645     }
646 }
647 
648 #[cfg(test)]
649 mod tests {
650     #[cfg(test)]
651     mod special {
652         use super::super::*;
653 
654         #[test]
655         fn call_immediate() {
656             let mut program = BpfCode::new();
657             program.call().set_imm(0x11_22_33_44).push();
658 
659             assert_eq!(
660                 program.into_bytes(),
661                 &[0x85, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
662             );
663         }
664 
665         #[test]
666         fn exit_operation() {
667             let mut program = BpfCode::new();
668             program.exit().push();
669 
670             assert_eq!(
671                 program.into_bytes(),
672                 &[0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
673             );
674         }
675     }
676 
677     #[cfg(test)]
678     mod jump_instructions {
679         #[cfg(test)]
680         mod register {
681             use super::super::super::*;
682 
683             #[test]
684             fn jump_on_dst_equals_src() {
685                 let mut program = BpfCode::new();
686                 program
687                     .jump_conditional(Cond::Equals, Source::Reg)
688                     .set_dst(0x01)
689                     .set_src(0x02)
690                     .push();
691 
692                 assert_eq!(
693                     program.into_bytes(),
694                     &[0x1d, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
695                 );
696             }
697 
698             #[test]
699             fn jump_on_dst_greater_than_src() {
700                 let mut program = BpfCode::new();
701                 program
702                     .jump_conditional(Cond::Greater, Source::Reg)
703                     .set_dst(0x03)
704                     .set_src(0x02)
705                     .push();
706 
707                 assert_eq!(
708                     program.into_bytes(),
709                     &[0x2d, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
710                 );
711             }
712 
713             #[test]
714             fn jump_on_dst_greater_or_equals_to_src() {
715                 let mut program = BpfCode::new();
716                 program
717                     .jump_conditional(Cond::GreaterEquals, Source::Reg)
718                     .set_dst(0x04)
719                     .set_src(0x01)
720                     .push();
721 
722                 assert_eq!(
723                     program.into_bytes(),
724                     &[0x3d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
725                 );
726             }
727 
728             #[test]
729             fn jump_on_dst_lower_than_src() {
730                 let mut program = BpfCode::new();
731                 program
732                     .jump_conditional(Cond::Lower, Source::Reg)
733                     .set_dst(0x03)
734                     .set_src(0x02)
735                     .push();
736 
737                 assert_eq!(
738                     program.into_bytes(),
739                     &[0xad, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
740                 );
741             }
742 
743             #[test]
744             fn jump_on_dst_lower_or_equals_to_src() {
745                 let mut program = BpfCode::new();
746                 program
747                     .jump_conditional(Cond::LowerEquals, Source::Reg)
748                     .set_dst(0x04)
749                     .set_src(0x01)
750                     .push();
751 
752                 assert_eq!(
753                     program.into_bytes(),
754                     &[0xbd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
755                 );
756             }
757 
758             #[test]
759             fn jump_on_dst_bit_and_with_src_not_equal_zero() {
760                 let mut program = BpfCode::new();
761                 program
762                     .jump_conditional(Cond::BitAnd, Source::Reg)
763                     .set_dst(0x05)
764                     .set_src(0x02)
765                     .push();
766 
767                 assert_eq!(
768                     program.into_bytes(),
769                     &[0x4d, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
770                 );
771             }
772 
773             #[test]
774             fn jump_on_dst_not_equals_src() {
775                 let mut program = BpfCode::new();
776                 program
777                     .jump_conditional(Cond::NotEquals, Source::Reg)
778                     .set_dst(0x03)
779                     .set_src(0x05)
780                     .push();
781 
782                 assert_eq!(
783                     program.into_bytes(),
784                     &[0x5d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
785                 );
786             }
787 
788             #[test]
789             fn jump_on_dst_greater_than_src_signed() {
790                 let mut program = BpfCode::new();
791                 program
792                     .jump_conditional(Cond::GreaterSigned, Source::Reg)
793                     .set_dst(0x04)
794                     .set_src(0x01)
795                     .push();
796 
797                 assert_eq!(
798                     program.into_bytes(),
799                     &[0x6d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
800                 );
801             }
802 
803             #[test]
804             fn jump_on_dst_greater_or_equals_src_signed() {
805                 let mut program = BpfCode::new();
806                 program
807                     .jump_conditional(Cond::GreaterEqualsSigned, Source::Reg)
808                     .set_dst(0x01)
809                     .set_src(0x03)
810                     .push();
811 
812                 assert_eq!(
813                     program.into_bytes(),
814                     &[0x7d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
815                 );
816             }
817 
818             #[test]
819             fn jump_on_dst_lower_than_src_signed() {
820                 let mut program = BpfCode::new();
821                 program
822                     .jump_conditional(Cond::LowerSigned, Source::Reg)
823                     .set_dst(0x04)
824                     .set_src(0x01)
825                     .push();
826 
827                 assert_eq!(
828                     program.into_bytes(),
829                     &[0xcd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
830                 );
831             }
832 
833             #[test]
834             fn jump_on_dst_lower_or_equals_src_signed() {
835                 let mut program = BpfCode::new();
836                 program
837                     .jump_conditional(Cond::LowerEqualsSigned, Source::Reg)
838                     .set_dst(0x01)
839                     .set_src(0x03)
840                     .push();
841 
842                 assert_eq!(
843                     program.into_bytes(),
844                     &[0xdd, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
845                 );
846             }
847         }
848 
849         #[cfg(test)]
850         mod immediate {
851             use super::super::super::*;
852 
853             #[test]
854             fn jump_to_label() {
855                 let mut program = BpfCode::new();
856                 program.jump_unconditional().set_off(0x00_11).push();
857 
858                 assert_eq!(
859                     program.into_bytes(),
860                     &[0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]
861                 );
862             }
863 
864             #[test]
865             fn jump_on_dst_equals_const() {
866                 let mut program = BpfCode::new();
867                 program
868                     .jump_conditional(Cond::Equals, Source::Imm)
869                     .set_dst(0x01)
870                     .set_imm(0x00_11_22_33)
871                     .push();
872 
873                 assert_eq!(
874                     program.into_bytes(),
875                     &[0x15, 0x01, 0x00, 0x00, 0x33, 0x22, 0x11, 0x00]
876                 );
877             }
878 
879             #[test]
880             fn jump_on_dst_greater_than_const() {
881                 let mut program = BpfCode::new();
882                 program
883                     .jump_conditional(Cond::Greater, Source::Imm)
884                     .set_dst(0x02)
885                     .set_imm(0x00_11_00_11)
886                     .push();
887 
888                 assert_eq!(
889                     program.into_bytes(),
890                     &[0x25, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]
891                 );
892             }
893 
894             #[test]
895             fn jump_on_dst_greater_or_equals_to_const() {
896                 let mut program = BpfCode::new();
897                 program
898                     .jump_conditional(Cond::GreaterEquals, Source::Imm)
899                     .set_dst(0x04)
900                     .set_imm(0x00_22_11_00)
901                     .push();
902 
903                 assert_eq!(
904                     program.into_bytes(),
905                     &[0x35, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]
906                 );
907             }
908 
909             #[test]
910             fn jump_on_dst_lower_than_const() {
911                 let mut program = BpfCode::new();
912                 program
913                     .jump_conditional(Cond::Lower, Source::Imm)
914                     .set_dst(0x02)
915                     .set_imm(0x00_11_00_11)
916                     .push();
917 
918                 assert_eq!(
919                     program.into_bytes(),
920                     &[0xa5, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]
921                 );
922             }
923 
924             #[test]
925             fn jump_on_dst_lower_or_equals_to_const() {
926                 let mut program = BpfCode::new();
927                 program
928                     .jump_conditional(Cond::LowerEquals, Source::Imm)
929                     .set_dst(0x04)
930                     .set_imm(0x00_22_11_00)
931                     .push();
932 
933                 assert_eq!(
934                     program.into_bytes(),
935                     &[0xb5, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]
936                 );
937             }
938 
939             #[test]
940             fn jump_on_dst_bit_and_with_const_not_equal_zero() {
941                 let mut program = BpfCode::new();
942                 program
943                     .jump_conditional(Cond::BitAnd, Source::Imm)
944                     .set_dst(0x05)
945                     .push();
946 
947                 assert_eq!(
948                     program.into_bytes(),
949                     &[0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
950                 );
951             }
952 
953             #[test]
954             fn jump_on_dst_not_equals_const() {
955                 let mut program = BpfCode::new();
956                 program
957                     .jump_conditional(Cond::NotEquals, Source::Imm)
958                     .set_dst(0x03)
959                     .push();
960 
961                 assert_eq!(
962                     program.into_bytes(),
963                     &[0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
964                 );
965             }
966 
967             #[test]
968             fn jump_on_dst_greater_than_const_signed() {
969                 let mut program = BpfCode::new();
970                 program
971                     .jump_conditional(Cond::GreaterSigned, Source::Imm)
972                     .set_dst(0x04)
973                     .push();
974 
975                 assert_eq!(
976                     program.into_bytes(),
977                     &[0x65, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
978                 );
979             }
980 
981             #[test]
982             fn jump_on_dst_greater_or_equals_src_signed() {
983                 let mut program = BpfCode::new();
984                 program
985                     .jump_conditional(Cond::GreaterEqualsSigned, Source::Imm)
986                     .set_dst(0x01)
987                     .push();
988 
989                 assert_eq!(
990                     program.into_bytes(),
991                     &[0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
992                 );
993             }
994 
995             #[test]
996             fn jump_on_dst_lower_than_const_signed() {
997                 let mut program = BpfCode::new();
998                 program
999                     .jump_conditional(Cond::LowerSigned, Source::Imm)
1000                     .set_dst(0x04)
1001                     .push();
1002 
1003                 assert_eq!(
1004                     program.into_bytes(),
1005                     &[0xc5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1006                 );
1007             }
1008 
1009             #[test]
1010             fn jump_on_dst_lower_or_equals_src_signed() {
1011                 let mut program = BpfCode::new();
1012                 program
1013                     .jump_conditional(Cond::LowerEqualsSigned, Source::Imm)
1014                     .set_dst(0x01)
1015                     .push();
1016 
1017                 assert_eq!(
1018                     program.into_bytes(),
1019                     &[0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1020                 );
1021             }
1022         }
1023     }
1024 
1025     #[cfg(test)]
1026     mod store_instructions {
1027         use super::super::*;
1028 
1029         #[test]
1030         fn store_word_from_dst_into_immediate_address() {
1031             let mut program = BpfCode::new();
1032             program
1033                 .store(MemSize::Word)
1034                 .set_dst(0x01)
1035                 .set_off(0x00_11)
1036                 .set_imm(0x11_22_33_44)
1037                 .push();
1038 
1039             assert_eq!(
1040                 program.into_bytes(),
1041                 &[0x62, 0x01, 0x11, 0x00, 0x44, 0x33, 0x22, 0x11]
1042             );
1043         }
1044 
1045         #[test]
1046         fn store_half_word_from_dst_into_immediate_address() {
1047             let mut program = BpfCode::new();
1048             program
1049                 .store(MemSize::HalfWord)
1050                 .set_dst(0x02)
1051                 .set_off(0x11_22)
1052                 .push();
1053 
1054             assert_eq!(
1055                 program.into_bytes(),
1056                 &[0x6a, 0x02, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]
1057             );
1058         }
1059 
1060         #[test]
1061         fn store_byte_from_dst_into_immediate_address() {
1062             let mut program = BpfCode::new();
1063             program.store(MemSize::Byte).push();
1064 
1065             assert_eq!(
1066                 program.into_bytes(),
1067                 &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1068             );
1069         }
1070 
1071         #[test]
1072         fn store_double_word_from_dst_into_immediate_address() {
1073             let mut program = BpfCode::new();
1074             program.store(MemSize::DoubleWord).push();
1075 
1076             assert_eq!(
1077                 program.into_bytes(),
1078                 &[0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1079             );
1080         }
1081 
1082         #[test]
1083         fn store_word_from_dst_into_src_address() {
1084             let mut program = BpfCode::new();
1085             program
1086                 .store_x(MemSize::Word)
1087                 .set_dst(0x01)
1088                 .set_src(0x02)
1089                 .push();
1090 
1091             assert_eq!(
1092                 program.into_bytes(),
1093                 &[0x63, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1094             );
1095         }
1096 
1097         #[test]
1098         fn store_half_word_from_dst_into_src_address() {
1099             let mut program = BpfCode::new();
1100             program.store_x(MemSize::HalfWord).push();
1101 
1102             assert_eq!(
1103                 program.into_bytes(),
1104                 &[0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1105             );
1106         }
1107 
1108         #[test]
1109         fn store_byte_from_dst_into_src_address() {
1110             let mut program = BpfCode::new();
1111             program.store_x(MemSize::Byte).push();
1112 
1113             assert_eq!(
1114                 program.into_bytes(),
1115                 &[0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1116             );
1117         }
1118 
1119         #[test]
1120         fn store_double_word_from_dst_into_src_address() {
1121             let mut program = BpfCode::new();
1122             program.store_x(MemSize::DoubleWord).push();
1123 
1124             assert_eq!(
1125                 program.into_bytes(),
1126                 &[0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1127             );
1128         }
1129     }
1130 
1131     #[cfg(test)]
1132     mod load_instructions {
1133         #[cfg(test)]
1134         mod register {
1135             use super::super::super::*;
1136 
1137             #[test]
1138             fn load_word_from_set_src_with_offset() {
1139                 let mut program = BpfCode::new();
1140                 program
1141                     .load_x(MemSize::Word)
1142                     .set_dst(0x01)
1143                     .set_src(0x02)
1144                     .set_off(0x00_02)
1145                     .push();
1146 
1147                 assert_eq!(
1148                     program.into_bytes(),
1149                     &[0x61, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00]
1150                 );
1151             }
1152 
1153             #[test]
1154             fn load_half_word_from_set_src_with_offset() {
1155                 let mut program = BpfCode::new();
1156                 program
1157                     .load_x(MemSize::HalfWord)
1158                     .set_dst(0x02)
1159                     .set_src(0x01)
1160                     .set_off(0x11_22)
1161                     .push();
1162 
1163                 assert_eq!(
1164                     program.into_bytes(),
1165                     &[0x69, 0x12, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]
1166                 );
1167             }
1168 
1169             #[test]
1170             fn load_byte_from_set_src_with_offset() {
1171                 let mut program = BpfCode::new();
1172                 program
1173                     .load_x(MemSize::Byte)
1174                     .set_dst(0x01)
1175                     .set_src(0x04)
1176                     .set_off(0x00_11)
1177                     .push();
1178 
1179                 assert_eq!(
1180                     program.into_bytes(),
1181                     &[0x71, 0x41, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]
1182                 );
1183             }
1184 
1185             #[test]
1186             fn load_double_word_from_set_src_with_offset() {
1187                 let mut program = BpfCode::new();
1188                 program
1189                     .load_x(MemSize::DoubleWord)
1190                     .set_dst(0x04)
1191                     .set_src(0x05)
1192                     .set_off(0x44_55)
1193                     .push();
1194 
1195                 assert_eq!(
1196                     program.into_bytes(),
1197                     &[0x79, 0x54, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00]
1198                 );
1199             }
1200         }
1201 
1202         #[cfg(test)]
1203         mod immediate {
1204             use super::super::super::*;
1205 
1206             #[test]
1207             fn load_double_word() {
1208                 let mut program = BpfCode::new();
1209                 program
1210                     .load(MemSize::DoubleWord)
1211                     .set_dst(0x01)
1212                     .set_imm(0x00_01_02_03)
1213                     .push();
1214 
1215                 assert_eq!(
1216                     program.into_bytes(),
1217                     &[0x18, 0x01, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
1218                 );
1219             }
1220 
1221             #[test]
1222             fn load_abs_word() {
1223                 let mut program = BpfCode::new();
1224                 program.load_abs(MemSize::Word).push();
1225 
1226                 assert_eq!(
1227                     program.into_bytes(),
1228                     &[0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1229                 );
1230             }
1231 
1232             #[test]
1233             fn load_abs_half_word() {
1234                 let mut program = BpfCode::new();
1235                 program.load_abs(MemSize::HalfWord).set_dst(0x05).push();
1236 
1237                 assert_eq!(
1238                     program.into_bytes(),
1239                     &[0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1240                 );
1241             }
1242 
1243             #[test]
1244             fn load_abs_byte() {
1245                 let mut program = BpfCode::new();
1246                 program.load_abs(MemSize::Byte).set_dst(0x01).push();
1247 
1248                 assert_eq!(
1249                     program.into_bytes(),
1250                     &[0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1251                 );
1252             }
1253 
1254             #[test]
1255             fn load_abs_double_word() {
1256                 let mut program = BpfCode::new();
1257                 program
1258                     .load_abs(MemSize::DoubleWord)
1259                     .set_dst(0x01)
1260                     .set_imm(0x01_02_03_04)
1261                     .push();
1262 
1263                 assert_eq!(
1264                     program.into_bytes(),
1265                     &[0x38, 0x01, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
1266                 );
1267             }
1268 
1269             #[test]
1270             fn load_indirect_word() {
1271                 let mut program = BpfCode::new();
1272                 program.load_ind(MemSize::Word).push();
1273 
1274                 assert_eq!(
1275                     program.into_bytes(),
1276                     &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1277                 );
1278             }
1279 
1280             #[test]
1281             fn load_indirect_half_word() {
1282                 let mut program = BpfCode::new();
1283                 program.load_ind(MemSize::HalfWord).push();
1284 
1285                 assert_eq!(
1286                     program.into_bytes(),
1287                     &[0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1288                 );
1289             }
1290 
1291             #[test]
1292             fn load_indirect_byte() {
1293                 let mut program = BpfCode::new();
1294                 program.load_ind(MemSize::Byte).push();
1295 
1296                 assert_eq!(
1297                     program.into_bytes(),
1298                     &[0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1299                 );
1300             }
1301 
1302             #[test]
1303             fn load_indirect_double_word() {
1304                 let mut program = BpfCode::new();
1305                 program.load_ind(MemSize::DoubleWord).push();
1306 
1307                 assert_eq!(
1308                     program.into_bytes(),
1309                     &[0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1310                 );
1311             }
1312         }
1313     }
1314 
1315     #[cfg(test)]
1316     mod byte_swap_instructions {
1317         use super::super::*;
1318 
1319         #[test]
1320         fn convert_host_to_little_endian_16bits() {
1321             let mut program = BpfCode::new();
1322             program
1323                 .swap_bytes(Endian::Little)
1324                 .set_dst(0x01)
1325                 .set_imm(0x00_00_00_10)
1326                 .push();
1327 
1328             assert_eq!(
1329                 program.into_bytes(),
1330                 &[0xd4, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]
1331             );
1332         }
1333 
1334         #[test]
1335         fn convert_host_to_little_endian_32bits() {
1336             let mut program = BpfCode::new();
1337             program
1338                 .swap_bytes(Endian::Little)
1339                 .set_dst(0x02)
1340                 .set_imm(0x00_00_00_20)
1341                 .push();
1342 
1343             assert_eq!(
1344                 program.into_bytes(),
1345                 &[0xd4, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]
1346             );
1347         }
1348 
1349         #[test]
1350         fn convert_host_to_little_endian_64bit() {
1351             let mut program = BpfCode::new();
1352             program
1353                 .swap_bytes(Endian::Little)
1354                 .set_dst(0x03)
1355                 .set_imm(0x00_00_00_40)
1356                 .push();
1357 
1358             assert_eq!(
1359                 program.into_bytes(),
1360                 &[0xd4, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]
1361             );
1362         }
1363 
1364         #[test]
1365         fn convert_host_to_big_endian_16bits() {
1366             let mut program = BpfCode::new();
1367             program
1368                 .swap_bytes(Endian::Big)
1369                 .set_dst(0x01)
1370                 .set_imm(0x00_00_00_10)
1371                 .push();
1372 
1373             assert_eq!(
1374                 program.into_bytes(),
1375                 &[0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]
1376             );
1377         }
1378 
1379         #[test]
1380         fn convert_host_to_big_endian_32bits() {
1381             let mut program = BpfCode::new();
1382             program
1383                 .swap_bytes(Endian::Big)
1384                 .set_dst(0x02)
1385                 .set_imm(0x00_00_00_20)
1386                 .push();
1387 
1388             assert_eq!(
1389                 program.into_bytes(),
1390                 &[0xdc, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]
1391             );
1392         }
1393 
1394         #[test]
1395         fn convert_host_to_big_endian_64bit() {
1396             let mut program = BpfCode::new();
1397             program
1398                 .swap_bytes(Endian::Big)
1399                 .set_dst(0x03)
1400                 .set_imm(0x00_00_00_40)
1401                 .push();
1402 
1403             assert_eq!(
1404                 program.into_bytes(),
1405                 &[0xdc, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]
1406             );
1407         }
1408     }
1409 
1410     #[cfg(test)]
1411     mod moves_instructions {
1412         #[cfg(test)]
1413         mod arch_x64 {
1414             #[cfg(test)]
1415             mod immediate {
1416                 use super::super::super::super::*;
1417 
1418                 #[test]
1419                 fn move_and_add_const_to_register() {
1420                     let mut program = BpfCode::new();
1421                     program
1422                         .add(Source::Imm, Arch::X64)
1423                         .set_dst(0x02)
1424                         .set_imm(0x01_02_03_04)
1425                         .push();
1426 
1427                     assert_eq!(
1428                         program.into_bytes(),
1429                         &[0x07, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
1430                     );
1431                 }
1432 
1433                 #[test]
1434                 fn move_sub_const_to_register() {
1435                     let mut program = BpfCode::new();
1436                     program
1437                         .sub(Source::Imm, Arch::X64)
1438                         .set_dst(0x04)
1439                         .set_imm(0x00_01_02_03)
1440                         .push();
1441 
1442                     assert_eq!(
1443                         program.into_bytes(),
1444                         &[0x17, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
1445                     );
1446                 }
1447 
1448                 #[test]
1449                 fn move_mul_const_to_register() {
1450                     let mut program = BpfCode::new();
1451                     program
1452                         .mul(Source::Imm, Arch::X64)
1453                         .set_dst(0x05)
1454                         .set_imm(0x04_03_02_01)
1455                         .push();
1456 
1457                     assert_eq!(
1458                         program.into_bytes(),
1459                         &[0x27, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]
1460                     );
1461                 }
1462 
1463                 #[test]
1464                 fn move_div_constant_to_register() {
1465                     let mut program = BpfCode::new();
1466                     program
1467                         .div(Source::Imm, Arch::X64)
1468                         .set_dst(0x02)
1469                         .set_imm(0x00_ff_00_ff)
1470                         .push();
1471 
1472                     assert_eq!(
1473                         program.into_bytes(),
1474                         &[0x37, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]
1475                     );
1476                 }
1477 
1478                 #[test]
1479                 fn move_bit_or_const_to_register() {
1480                     let mut program = BpfCode::new();
1481                     program
1482                         .bit_or(Source::Imm, Arch::X64)
1483                         .set_dst(0x02)
1484                         .set_imm(0x00_11_00_22)
1485                         .push();
1486 
1487                     assert_eq!(
1488                         program.into_bytes(),
1489                         &[0x47, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]
1490                     );
1491                 }
1492 
1493                 #[test]
1494                 fn move_bit_and_const_to_register() {
1495                     let mut program = BpfCode::new();
1496                     program
1497                         .bit_and(Source::Imm, Arch::X64)
1498                         .set_dst(0x02)
1499                         .set_imm(0x11_22_33_44)
1500                         .push();
1501 
1502                     assert_eq!(
1503                         program.into_bytes(),
1504                         &[0x57, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
1505                     );
1506                 }
1507 
1508                 #[test]
1509                 fn move_left_shift_const_to_register() {
1510                     let mut program = BpfCode::new();
1511                     program
1512                         .left_shift(Source::Imm, Arch::X64)
1513                         .set_dst(0x01)
1514                         .push();
1515 
1516                     assert_eq!(
1517                         program.into_bytes(),
1518                         &[0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1519                     );
1520                 }
1521 
1522                 #[test]
1523                 fn move_logical_right_shift_const_to_register() {
1524                     let mut program = BpfCode::new();
1525                     program
1526                         .right_shift(Source::Imm, Arch::X64)
1527                         .set_dst(0x01)
1528                         .push();
1529 
1530                     assert_eq!(
1531                         program.into_bytes(),
1532                         &[0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1533                     );
1534                 }
1535 
1536                 #[test]
1537                 fn move_negate_register() {
1538                     let mut program = BpfCode::new();
1539                     program.negate(Arch::X64).set_dst(0x02).push();
1540 
1541                     assert_eq!(
1542                         program.into_bytes(),
1543                         &[0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1544                     );
1545                 }
1546 
1547                 #[test]
1548                 fn move_mod_const_to_register() {
1549                     let mut program = BpfCode::new();
1550                     program.modulo(Source::Imm, Arch::X64).set_dst(0x02).push();
1551 
1552                     assert_eq!(
1553                         program.into_bytes(),
1554                         &[0x97, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1555                     );
1556                 }
1557 
1558                 #[test]
1559                 fn move_bit_xor_const_to_register() {
1560                     let mut program = BpfCode::new();
1561                     program.bit_xor(Source::Imm, Arch::X64).set_dst(0x03).push();
1562 
1563                     assert_eq!(
1564                         program.into_bytes(),
1565                         &[0xa7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1566                     );
1567                 }
1568 
1569                 #[test]
1570                 fn move_const_to_register() {
1571                     let mut program = BpfCode::new();
1572                     program
1573                         .mov(Source::Imm, Arch::X64)
1574                         .set_dst(0x01)
1575                         .set_imm(0x00_00_00_FF)
1576                         .push();
1577 
1578                     assert_eq!(
1579                         program.into_bytes(),
1580                         &[0xb7, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]
1581                     );
1582                 }
1583 
1584                 #[test]
1585                 fn move_signed_right_shift_const_to_register() {
1586                     let mut program = BpfCode::new();
1587                     program
1588                         .signed_right_shift(Source::Imm, Arch::X64)
1589                         .set_dst(0x05)
1590                         .push();
1591 
1592                     assert_eq!(
1593                         program.into_bytes(),
1594                         &[0xc7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1595                     );
1596                 }
1597             }
1598 
1599             #[cfg(test)]
1600             mod register {
1601                 use super::super::super::super::*;
1602 
1603                 #[test]
1604                 fn move_and_add_from_register() {
1605                     let mut program = BpfCode::new();
1606                     program
1607                         .add(Source::Reg, Arch::X64)
1608                         .set_dst(0x03)
1609                         .set_src(0x02)
1610                         .push();
1611 
1612                     assert_eq!(
1613                         program.into_bytes(),
1614                         &[0x0f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1615                     );
1616                 }
1617 
1618                 #[test]
1619                 fn move_sub_from_register_to_register() {
1620                     let mut program = BpfCode::new();
1621                     program
1622                         .sub(Source::Reg, Arch::X64)
1623                         .set_dst(0x03)
1624                         .set_src(0x04)
1625                         .push();
1626 
1627                     assert_eq!(
1628                         program.into_bytes(),
1629                         &[0x1f, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1630                     );
1631                 }
1632 
1633                 #[test]
1634                 fn move_mul_from_register_to_register() {
1635                     let mut program = BpfCode::new();
1636                     program
1637                         .mul(Source::Reg, Arch::X64)
1638                         .set_dst(0x04)
1639                         .set_src(0x03)
1640                         .push();
1641 
1642                     assert_eq!(
1643                         program.into_bytes(),
1644                         &[0x2f, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1645                     );
1646                 }
1647 
1648                 #[test]
1649                 fn move_div_from_register_to_register() {
1650                     let mut program = BpfCode::new();
1651                     program
1652                         .div(Source::Reg, Arch::X64)
1653                         .set_dst(0x01)
1654                         .set_src(0x00)
1655                         .push();
1656 
1657                     assert_eq!(
1658                         program.into_bytes(),
1659                         &[0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1660                     );
1661                 }
1662 
1663                 #[test]
1664                 fn move_bit_or_from_register_to_register() {
1665                     let mut program = BpfCode::new();
1666                     program
1667                         .bit_or(Source::Reg, Arch::X64)
1668                         .set_dst(0x03)
1669                         .set_src(0x01)
1670                         .push();
1671 
1672                     assert_eq!(
1673                         program.into_bytes(),
1674                         &[0x4f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1675                     );
1676                 }
1677 
1678                 #[test]
1679                 fn move_bit_and_from_register_to_register() {
1680                     let mut program = BpfCode::new();
1681                     program
1682                         .bit_and(Source::Reg, Arch::X64)
1683                         .set_dst(0x03)
1684                         .set_src(0x02)
1685                         .push();
1686 
1687                     assert_eq!(
1688                         program.into_bytes(),
1689                         &[0x5f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1690                     );
1691                 }
1692 
1693                 #[test]
1694                 fn move_left_shift_from_register_to_register() {
1695                     let mut program = BpfCode::new();
1696                     program
1697                         .left_shift(Source::Reg, Arch::X64)
1698                         .set_dst(0x02)
1699                         .set_src(0x03)
1700                         .push();
1701 
1702                     assert_eq!(
1703                         program.into_bytes(),
1704                         &[0x6f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1705                     );
1706                 }
1707 
1708                 #[test]
1709                 fn move_logical_right_shift_from_register_to_register() {
1710                     let mut program = BpfCode::new();
1711                     program
1712                         .right_shift(Source::Reg, Arch::X64)
1713                         .set_dst(0x02)
1714                         .set_src(0x04)
1715                         .push();
1716 
1717                     assert_eq!(
1718                         program.into_bytes(),
1719                         &[0x7f, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1720                     );
1721                 }
1722 
1723                 #[test]
1724                 fn move_mod_from_register_to_register() {
1725                     let mut program = BpfCode::new();
1726                     program
1727                         .modulo(Source::Reg, Arch::X64)
1728                         .set_dst(0x01)
1729                         .set_src(0x02)
1730                         .push();
1731 
1732                     assert_eq!(
1733                         program.into_bytes(),
1734                         &[0x9f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1735                     );
1736                 }
1737 
1738                 #[test]
1739                 fn move_bit_xor_from_register_to_register() {
1740                     let mut program = BpfCode::new();
1741                     program
1742                         .bit_xor(Source::Reg, Arch::X64)
1743                         .set_dst(0x02)
1744                         .set_src(0x04)
1745                         .push();
1746 
1747                     assert_eq!(
1748                         program.into_bytes(),
1749                         &[0xaf, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1750                     );
1751                 }
1752 
1753                 #[test]
1754                 fn move_from_register_to_another_register() {
1755                     let mut program = BpfCode::new();
1756                     program.mov(Source::Reg, Arch::X64).set_src(0x01).push();
1757 
1758                     assert_eq!(
1759                         program.into_bytes(),
1760                         &[0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1761                     );
1762                 }
1763 
1764                 #[test]
1765                 fn move_signed_right_shift_from_register_to_register() {
1766                     let mut program = BpfCode::new();
1767                     program
1768                         .signed_right_shift(Source::Reg, Arch::X64)
1769                         .set_dst(0x02)
1770                         .set_src(0x03)
1771                         .push();
1772 
1773                     assert_eq!(
1774                         program.into_bytes(),
1775                         &[0xcf, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1776                     );
1777                 }
1778             }
1779         }
1780 
1781         #[cfg(test)]
1782         mod arch_x32 {
1783             #[cfg(test)]
1784             mod immediate {
1785                 use super::super::super::super::*;
1786 
1787                 #[test]
1788                 fn move_and_add_const_to_register() {
1789                     let mut program = BpfCode::new();
1790                     program
1791                         .add(Source::Imm, Arch::X32)
1792                         .set_dst(0x02)
1793                         .set_imm(0x01_02_03_04)
1794                         .push();
1795 
1796                     assert_eq!(
1797                         program.into_bytes(),
1798                         &[0x04, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]
1799                     );
1800                 }
1801 
1802                 #[test]
1803                 fn move_sub_const_to_register() {
1804                     let mut program = BpfCode::new();
1805                     program
1806                         .sub(Source::Imm, Arch::X32)
1807                         .set_dst(0x04)
1808                         .set_imm(0x00_01_02_03)
1809                         .push();
1810 
1811                     assert_eq!(
1812                         program.into_bytes(),
1813                         &[0x14, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]
1814                     );
1815                 }
1816 
1817                 #[test]
1818                 fn move_mul_const_to_register() {
1819                     let mut program = BpfCode::new();
1820                     program
1821                         .mul(Source::Imm, Arch::X32)
1822                         .set_dst(0x05)
1823                         .set_imm(0x04_03_02_01)
1824                         .push();
1825 
1826                     assert_eq!(
1827                         program.into_bytes(),
1828                         &[0x24, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]
1829                     );
1830                 }
1831 
1832                 #[test]
1833                 fn move_div_constant_to_register() {
1834                     let mut program = BpfCode::new();
1835                     program
1836                         .div(Source::Imm, Arch::X32)
1837                         .set_dst(0x02)
1838                         .set_imm(0x00_ff_00_ff)
1839                         .push();
1840 
1841                     assert_eq!(
1842                         program.into_bytes(),
1843                         &[0x34, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]
1844                     );
1845                 }
1846 
1847                 #[test]
1848                 fn move_bit_or_const_to_register() {
1849                     let mut program = BpfCode::new();
1850                     program
1851                         .bit_or(Source::Imm, Arch::X32)
1852                         .set_dst(0x02)
1853                         .set_imm(0x00_11_00_22)
1854                         .push();
1855 
1856                     assert_eq!(
1857                         program.into_bytes(),
1858                         &[0x44, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]
1859                     );
1860                 }
1861 
1862                 #[test]
1863                 fn move_bit_and_const_to_register() {
1864                     let mut program = BpfCode::new();
1865                     program
1866                         .bit_and(Source::Imm, Arch::X32)
1867                         .set_dst(0x02)
1868                         .set_imm(0x11_22_33_44)
1869                         .push();
1870 
1871                     assert_eq!(
1872                         program.into_bytes(),
1873                         &[0x54, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]
1874                     );
1875                 }
1876 
1877                 #[test]
1878                 fn move_left_shift_const_to_register() {
1879                     let mut program = BpfCode::new();
1880                     program
1881                         .left_shift(Source::Imm, Arch::X32)
1882                         .set_dst(0x01)
1883                         .push();
1884 
1885                     assert_eq!(
1886                         program.into_bytes(),
1887                         &[0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1888                     );
1889                 }
1890 
1891                 #[test]
1892                 fn move_logical_right_shift_const_to_register() {
1893                     let mut program = BpfCode::new();
1894                     program
1895                         .right_shift(Source::Imm, Arch::X32)
1896                         .set_dst(0x01)
1897                         .push();
1898 
1899                     assert_eq!(
1900                         program.into_bytes(),
1901                         &[0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1902                     );
1903                 }
1904 
1905                 #[test]
1906                 fn move_negate_register() {
1907                     let mut program = BpfCode::new();
1908                     program.negate(Arch::X32).set_dst(0x02).push();
1909 
1910                     assert_eq!(
1911                         program.into_bytes(),
1912                         &[0x84, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1913                     );
1914                 }
1915 
1916                 #[test]
1917                 fn move_mod_const_to_register() {
1918                     let mut program = BpfCode::new();
1919                     program.modulo(Source::Imm, Arch::X32).set_dst(0x02).push();
1920 
1921                     assert_eq!(
1922                         program.into_bytes(),
1923                         &[0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1924                     );
1925                 }
1926 
1927                 #[test]
1928                 fn move_bit_xor_const_to_register() {
1929                     let mut program = BpfCode::new();
1930                     program.bit_xor(Source::Imm, Arch::X32).set_dst(0x03).push();
1931 
1932                     assert_eq!(
1933                         program.into_bytes(),
1934                         &[0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1935                     );
1936                 }
1937 
1938                 #[test]
1939                 fn move_const_to_register() {
1940                     let mut program = BpfCode::new();
1941                     program
1942                         .mov(Source::Imm, Arch::X32)
1943                         .set_dst(0x01)
1944                         .set_imm(0x00_00_00_FF)
1945                         .push();
1946 
1947                     assert_eq!(
1948                         program.into_bytes(),
1949                         &[0xb4, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]
1950                     );
1951                 }
1952 
1953                 #[test]
1954                 fn move_signed_right_shift_const_to_register() {
1955                     let mut program = BpfCode::new();
1956                     program
1957                         .signed_right_shift(Source::Imm, Arch::X32)
1958                         .set_dst(0x05)
1959                         .push();
1960 
1961                     assert_eq!(
1962                         program.into_bytes(),
1963                         &[0xc4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1964                     );
1965                 }
1966             }
1967 
1968             #[cfg(test)]
1969             mod register {
1970                 use super::super::super::super::*;
1971 
1972                 #[test]
1973                 fn move_and_add_from_register() {
1974                     let mut program = BpfCode::new();
1975                     program
1976                         .add(Source::Reg, Arch::X32)
1977                         .set_dst(0x03)
1978                         .set_src(0x02)
1979                         .push();
1980 
1981                     assert_eq!(
1982                         program.into_bytes(),
1983                         &[0x0c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1984                     );
1985                 }
1986 
1987                 #[test]
1988                 fn move_sub_from_register_to_register() {
1989                     let mut program = BpfCode::new();
1990                     program
1991                         .sub(Source::Reg, Arch::X32)
1992                         .set_dst(0x03)
1993                         .set_src(0x04)
1994                         .push();
1995 
1996                     assert_eq!(
1997                         program.into_bytes(),
1998                         &[0x1c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
1999                     );
2000                 }
2001 
2002                 #[test]
2003                 fn move_mul_from_register_to_register() {
2004                     let mut program = BpfCode::new();
2005                     program
2006                         .mul(Source::Reg, Arch::X32)
2007                         .set_dst(0x04)
2008                         .set_src(0x03)
2009                         .push();
2010 
2011                     assert_eq!(
2012                         program.into_bytes(),
2013                         &[0x2c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2014                     );
2015                 }
2016 
2017                 #[test]
2018                 fn move_div_from_register_to_register() {
2019                     let mut program = BpfCode::new();
2020                     program
2021                         .div(Source::Reg, Arch::X32)
2022                         .set_dst(0x01)
2023                         .set_src(0x00)
2024                         .push();
2025 
2026                     assert_eq!(
2027                         program.into_bytes(),
2028                         &[0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2029                     );
2030                 }
2031 
2032                 #[test]
2033                 fn move_bit_or_from_register_to_register() {
2034                     let mut program = BpfCode::new();
2035                     program
2036                         .bit_or(Source::Reg, Arch::X32)
2037                         .set_dst(0x03)
2038                         .set_src(0x01)
2039                         .push();
2040 
2041                     assert_eq!(
2042                         program.into_bytes(),
2043                         &[0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2044                     );
2045                 }
2046 
2047                 #[test]
2048                 fn move_bit_and_from_register_to_register() {
2049                     let mut program = BpfCode::new();
2050                     program
2051                         .bit_and(Source::Reg, Arch::X32)
2052                         .set_dst(0x03)
2053                         .set_src(0x02)
2054                         .push();
2055 
2056                     assert_eq!(
2057                         program.into_bytes(),
2058                         &[0x5c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2059                     );
2060                 }
2061 
2062                 #[test]
2063                 fn move_left_shift_from_register_to_register() {
2064                     let mut program = BpfCode::new();
2065                     program
2066                         .left_shift(Source::Reg, Arch::X32)
2067                         .set_dst(0x02)
2068                         .set_src(0x03)
2069                         .push();
2070 
2071                     assert_eq!(
2072                         program.into_bytes(),
2073                         &[0x6c, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2074                     );
2075                 }
2076 
2077                 #[test]
2078                 fn move_logical_right_shift_from_register_to_register() {
2079                     let mut program = BpfCode::new();
2080                     program
2081                         .right_shift(Source::Reg, Arch::X32)
2082                         .set_dst(0x02)
2083                         .set_src(0x04)
2084                         .push();
2085 
2086                     assert_eq!(
2087                         program.into_bytes(),
2088                         &[0x7c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2089                     );
2090                 }
2091 
2092                 #[test]
2093                 fn move_mod_from_register_to_register() {
2094                     let mut program = BpfCode::new();
2095                     program
2096                         .modulo(Source::Reg, Arch::X32)
2097                         .set_dst(0x01)
2098                         .set_src(0x02)
2099                         .push();
2100 
2101                     assert_eq!(
2102                         program.into_bytes(),
2103                         &[0x9c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2104                     );
2105                 }
2106 
2107                 #[test]
2108                 fn move_bit_xor_from_register_to_register() {
2109                     let mut program = BpfCode::new();
2110                     program
2111                         .bit_xor(Source::Reg, Arch::X32)
2112                         .set_dst(0x02)
2113                         .set_src(0x04)
2114                         .push();
2115 
2116                     assert_eq!(
2117                         program.into_bytes(),
2118                         &[0xac, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2119                     );
2120                 }
2121 
2122                 #[test]
2123                 fn move_from_register_to_another_register() {
2124                     let mut program = BpfCode::new();
2125                     program
2126                         .mov(Source::Reg, Arch::X32)
2127                         .set_dst(0x00)
2128                         .set_src(0x01)
2129                         .push();
2130 
2131                     assert_eq!(
2132                         program.into_bytes(),
2133                         &[0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2134                     );
2135                 }
2136 
2137                 #[test]
2138                 fn move_signed_right_shift_from_register_to_register() {
2139                     let mut program = BpfCode::new();
2140                     program
2141                         .signed_right_shift(Source::Reg, Arch::X32)
2142                         .set_dst(0x02)
2143                         .set_src(0x03)
2144                         .push();
2145 
2146                     assert_eq!(
2147                         program.into_bytes(),
2148                         &[0xcc, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
2149                     );
2150                 }
2151             }
2152         }
2153     }
2154 
2155     #[cfg(test)]
2156     mod programs {
2157         use super::super::*;
2158 
2159         #[test]
2160         fn example_from_assembler() {
2161             let mut program = BpfCode::new();
2162             program
2163                 .add(Source::Imm, Arch::X64)
2164                 .set_dst(1)
2165                 .set_imm(0x605)
2166                 .push()
2167                 .mov(Source::Imm, Arch::X64)
2168                 .set_dst(2)
2169                 .set_imm(0x32)
2170                 .push()
2171                 .mov(Source::Reg, Arch::X64)
2172                 .set_src(0)
2173                 .set_dst(1)
2174                 .push()
2175                 .swap_bytes(Endian::Big)
2176                 .set_dst(0)
2177                 .set_imm(0x10)
2178                 .push()
2179                 .negate(Arch::X64)
2180                 .set_dst(2)
2181                 .push()
2182                 .exit()
2183                 .push();
2184 
2185             let bytecode = program.into_bytes();
2186             let ref_prog = &[
2187                 0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00, 0xb7, 0x02, 0x00, 0x00, 0x32, 0x00,
2188                 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00,
2189                 0x10, 0x00, 0x00, 0x00, 0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00,
2190                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2191             ];
2192             // cargo says: "`[{integer}; 48]` cannot be formatted using `{:?}`
2193             //              because it doesn't implement `std::fmt::Debug`"
2194             // So let's check in two steps.
2195             assert_eq!(bytecode[..32], ref_prog[..32]);
2196             assert_eq!(bytecode[33..], ref_prog[33..]);
2197         }
2198     }
2199 }
2200