rbpf/
insn_builder.rs

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
6use ebpf::*;
7use crate::lib::*;
8
9/// Represents single eBPF instruction
10pub trait Instruction: Sized {
11    /// returns instruction opt code
12    fn opt_code_byte(&self) -> u8;
13
14    /// returns destination register
15    fn get_dst(&self) -> u8 {
16        self.get_insn().dst
17    }
18
19    /// returns source register
20    fn get_src(&self) -> u8 {
21        self.get_insn().src
22    }
23
24    /// returns offset bytes
25    fn get_off(&self) -> i16 {
26        self.get_insn().off
27    }
28
29    /// returns immediate value
30    fn get_imm(&self) -> i32 {
31        self.get_insn().imm
32    }
33
34    /// sets destination register
35    fn set_dst(mut self, dst: u8) -> Self {
36        self.get_insn_mut().dst = dst;
37        self
38    }
39
40    /// sets source register
41    fn set_src(mut self, src: u8) -> Self {
42        self.get_insn_mut().src = src;
43        self
44    }
45
46    /// sets offset bytes
47    fn set_off(mut self, offset: i16) -> Self {
48        self.get_insn_mut().off = offset;
49        self
50    }
51
52    /// sets immediate value
53    fn set_imm(mut self, imm: i32) -> Self {
54        self.get_insn_mut().imm = imm;
55        self
56    }
57
58    /// get `ebpf::Insn` struct
59    fn get_insn(&self) -> &Insn;
60
61    /// get mutable `ebpf::Insn` struct
62    fn get_insn_mut(&mut self) -> &mut Insn;
63}
64
65/// General trait for `Instruction`s and `BpfCode`.
66/// Provides functionality to transform `struct` into collection of bytes
67pub trait IntoBytes {
68    /// type of targeted transformation
69    type Bytes;
70
71    /// consume `Self` with transformation into `Self::Bytes`
72    fn into_bytes(self) -> Self::Bytes;
73}
74
75/// General implementation of `IntoBytes` for `Instruction`
76impl<'i, I: Instruction> IntoBytes for &'i I {
77    type Bytes = Vec<u8>;
78
79    /// transform immutable reference of `Instruction` into `Vec<u8>` with size of 8
80    /// [ 1 byte ,      1 byte      , 2 bytes,  4 bytes  ]
81    /// [ OP_CODE, SRC_REG | DST_REG, OFFSET , IMMEDIATE ]
82    fn into_bytes(self) -> Self::Bytes {
83        let buffer = vec![
84            self.opt_code_byte(),
85            self.get_src() << 4 | self.get_dst(),
86            self.get_off()          as u8,
87            (self.get_off() >> 8)   as u8,
88            self.get_imm()          as u8,
89            (self.get_imm() >> 8)   as u8,
90            (self.get_imm() >> 16)  as u8,
91            (self.get_imm() >> 24)  as u8,
92        ];
93        buffer
94    }
95}
96
97/// BPF instruction stack in byte representation
98#[derive(Default)]
99pub struct BpfCode {
100    instructions: Vec<u8>
101}
102
103impl BpfCode {
104    /// creates new empty BPF instruction stack
105    pub fn new() -> Self {
106        BpfCode { instructions: vec![] }
107    }
108
109    /// create ADD instruction
110    pub fn add(&mut self, source: Source, arch: Arch) -> Move {
111        self.mov_internal(source, arch, OpBits::Add)
112    }
113
114    /// create SUB instruction
115    pub fn sub(&mut self, source: Source, arch: Arch) -> Move {
116        self.mov_internal(source, arch, OpBits::Sub)
117    }
118
119    /// create MUL instruction
120    pub fn mul(&mut self, source: Source, arch: Arch) -> Move {
121        self.mov_internal(source, arch, OpBits::Mul)
122    }
123
124    /// create DIV instruction
125    pub fn div(&mut self, source: Source, arch: Arch) -> Move {
126        self.mov_internal(source, arch, OpBits::Div)
127    }
128
129    /// create OR instruction
130    pub fn bit_or(&mut self, source: Source, arch: Arch) -> Move {
131        self.mov_internal(source, arch, OpBits::BitOr)
132    }
133
134    /// create AND instruction
135    pub fn bit_and(&mut self, source: Source, arch: Arch) -> Move {
136        self.mov_internal(source, arch, OpBits::BitAnd)
137    }
138
139    /// create LSHIFT instruction
140    pub fn left_shift(&mut self, source: Source, arch: Arch) -> Move {
141        self.mov_internal(source, arch, OpBits::LShift)
142    }
143
144    /// create RSHIFT instruction
145    pub fn right_shift(&mut self, source: Source, arch: Arch) -> Move {
146        self.mov_internal(source, arch, OpBits::RShift)
147    }
148
149    /// create NEGATE instruction
150    pub fn negate(&mut self, arch: Arch) -> Move {
151        self.mov_internal(Source::Imm, arch, OpBits::Negate)
152    }
153
154    /// create MOD instruction
155    pub fn modulo(&mut self, source: Source, arch: Arch) -> Move {
156        self.mov_internal(source, arch, OpBits::Mod)
157    }
158
159    /// create XOR instruction
160    pub fn bit_xor(&mut self, source: Source, arch: Arch) -> Move {
161        self.mov_internal(source, arch, OpBits::BitXor)
162    }
163
164    /// create MOV instruction
165    pub fn mov(&mut self, source: Source, arch: Arch) -> Move {
166        self.mov_internal(source, arch, OpBits::Mov)
167    }
168
169    /// create SIGNED RSHIFT instruction
170    pub fn signed_right_shift(&mut self, source: Source, arch: Arch) -> Move {
171        self.mov_internal(source, arch, OpBits::SignRShift)
172    }
173
174    #[inline]
175    fn mov_internal(&mut self, source: Source, arch_bits: Arch, op_bits: OpBits) -> Move {
176        Move {
177            bpf_code: self,
178            src_bit: source,
179            op_bits,
180            arch_bits,
181            insn: Insn {
182                opc: 0x00,
183                dst: 0x00,
184                src: 0x00,
185                off: 0x00_00,
186                imm: 0x00_00_00_00
187            }
188        }
189    }
190
191    /// create byte swap instruction
192    pub fn swap_bytes(&mut self, endian: Endian) -> SwapBytes {
193        SwapBytes {
194            bpf_code: self,
195            endian,
196            insn: Insn {
197                opc: 0x00,
198                dst: 0x00,
199                src: 0x00,
200                off: 0x00_00,
201                imm: 0x00_00_00_00
202            }
203        }
204    }
205
206    /// create LOAD instruction, IMMEDIATE is the source
207    pub fn load(&mut self, mem_size: MemSize) -> Load {
208        self.load_internal(mem_size, Addressing::Imm, BPF_LD)
209    }
210
211    /// create ABSOLUTE LOAD instruction
212    pub fn load_abs(&mut self, mem_size: MemSize) -> Load {
213        self.load_internal(mem_size, Addressing::Abs, BPF_LD)
214    }
215
216    /// create INDIRECT LOAD instruction
217    pub fn load_ind(&mut self, mem_size: MemSize) -> Load {
218        self.load_internal(mem_size, Addressing::Ind, BPF_LD)
219    }
220
221    /// create LOAD instruction, MEMORY is the source
222    pub fn load_x(&mut self, mem_size: MemSize) -> Load {
223        self.load_internal(mem_size, Addressing::Mem, BPF_LDX)
224    }
225
226    #[inline]
227    fn load_internal(&mut self, mem_size: MemSize, addressing: Addressing, source: u8) -> Load {
228        Load {
229            bpf_code: self,
230            addressing,
231            mem_size,
232            source,
233            insn: Insn {
234                opc: 0x00,
235                dst: 0x00,
236                src: 0x00,
237                off: 0x00_00,
238                imm: 0x00_00_00_00
239            }
240        }
241    }
242
243    /// creates STORE instruction, IMMEDIATE is the source
244    pub fn store(&mut self, mem_size: MemSize) -> Store {
245        self.store_internal(mem_size, BPF_IMM)
246    }
247
248    /// creates STORE instruction, MEMORY is the source
249    pub fn store_x(&mut self, mem_size: MemSize) -> Store {
250        self.store_internal(mem_size, BPF_MEM | BPF_STX)
251    }
252
253    #[inline]
254    fn store_internal(&mut self, mem_size: MemSize, source: u8) -> Store {
255        Store {
256            bpf_code: self,
257            mem_size,
258            source,
259            insn: Insn {
260                opc: 0x00,
261                dst: 0x00,
262                src: 0x00,
263                off: 0x00_00,
264                imm: 0x00_00_00_00
265            }
266        }
267    }
268
269    /// create unconditional JMP instruction
270    pub fn jump_unconditional(&mut self) -> Jump {
271        self.jump_conditional(Cond::Abs, Source::Imm)
272    }
273
274    /// create conditional JMP instruction
275    pub fn jump_conditional(&mut self, cond: Cond, src_bit: Source) -> Jump {
276        Jump {
277            bpf_code: self,
278            cond,
279            src_bit,
280            insn: Insn {
281                opc: 0x00,
282                dst: 0x00,
283                src: 0x00,
284                off: 0x00_00,
285                imm: 0x00_00_00_00
286            }
287        }
288    }
289
290    /// create CALL instruction
291    pub fn call(&mut self) -> FunctionCall {
292        FunctionCall {
293            bpf_code: self,
294            insn: Insn {
295                opc: 0x00,
296                dst: 0x00,
297                src: 0x00,
298                off: 0x00_00,
299                imm: 0x00_00_00_00
300            }
301        }
302    }
303
304    /// create EXIT instruction
305    pub fn exit(&mut self) -> Exit {
306        Exit {
307            bpf_code: self,
308            insn: Insn {
309                opc: 0x00,
310                dst: 0x00,
311                src: 0x00,
312                off: 0x00_00,
313                imm: 0x00_00_00_00
314            }
315        }
316    }
317}
318
319/// Transform `BpfCode` into assemble representation
320impl<'a> IntoBytes for &'a BpfCode {
321    type Bytes = &'a [u8];
322
323    /// returns `BpfCode` instruction stack as `&[u8]`
324    fn into_bytes(self) -> Self::Bytes {
325        self.instructions.as_slice()
326    }
327}
328
329/// struct to represent `MOV ALU` instructions
330pub struct Move<'i> {
331    bpf_code: &'i mut BpfCode,
332    src_bit: Source,
333    op_bits: OpBits,
334    arch_bits: Arch,
335    insn: Insn
336}
337
338impl<'i> Move<'i> {
339    /// push MOV instruction into BpfCode instruction stack
340    pub fn push(self) -> &'i mut BpfCode {
341        let mut asm = self.into_bytes();
342        self.bpf_code.instructions.append(&mut asm);
343        self.bpf_code
344    }
345}
346
347impl<'i> Instruction for Move<'i> {
348    fn opt_code_byte(&self) -> u8 {
349        let op_bits = self.op_bits as u8;
350        let src_bit = self.src_bit as u8;
351        let arch_bits = self.arch_bits as u8;
352        op_bits | src_bit | arch_bits
353    }
354
355    fn get_insn_mut(&mut self) -> &mut Insn {
356        &mut self.insn
357    }
358
359    fn get_insn(&self) -> &Insn {
360        &self.insn
361    }
362}
363
364#[derive(Copy, Clone, PartialEq, Eq)]
365/// The source of ALU and JMP instructions
366pub enum Source {
367    /// immediate field will be used as a source
368    Imm = BPF_IMM as isize,
369    /// src register will be used as a source
370    Reg = BPF_X as isize
371}
372
373#[derive(Copy, Clone)]
374enum OpBits {
375    Add = BPF_ADD as isize,
376    Sub = BPF_SUB as isize,
377    Mul = BPF_MUL as isize,
378    Div = BPF_DIV as isize,
379    BitOr = BPF_OR as isize,
380    BitAnd = BPF_AND as isize,
381    LShift = BPF_LSH as isize,
382    RShift = BPF_RSH as isize,
383    Negate = BPF_NEG as isize,
384    Mod = BPF_MOD as isize,
385    BitXor = BPF_XOR as isize,
386    Mov = BPF_MOV as isize,
387    SignRShift = BPF_ARSH as isize
388}
389
390#[derive(Copy, Clone)]
391/// Architecture of instructions
392pub enum Arch {
393    /// 64-bit instructions
394    X64 = BPF_ALU64 as isize,
395    /// 32-bit instructions
396    X32 = BPF_ALU as isize
397}
398
399/// struct representation of byte swap operation
400pub struct SwapBytes<'i> {
401    bpf_code: &'i mut BpfCode,
402    endian: Endian,
403    insn: Insn
404}
405
406impl<'i> SwapBytes<'i> {
407    /// push bytes swap instruction into BpfCode instruction stack
408    pub fn push(self) -> &'i mut BpfCode {
409        let mut asm = self.into_bytes();
410        self.bpf_code.instructions.append(&mut asm);
411        self.bpf_code
412    }
413}
414
415impl<'i> Instruction for SwapBytes<'i> {
416    fn opt_code_byte(&self) -> u8 {
417        self.endian as u8
418    }
419
420    fn get_insn_mut(&mut self) -> &mut Insn {
421        &mut self.insn
422    }
423
424    fn get_insn(&self) -> &Insn {
425        &self.insn
426    }
427}
428
429#[derive(Copy, Clone)]
430/// Bytes endian
431pub enum Endian {
432    /// Little endian
433    Little = LE as isize,
434    /// Big endian
435    Big = BE as isize
436}
437
438/// struct representation of LOAD instructions
439pub struct Load<'i> {
440    bpf_code: &'i mut BpfCode,
441    addressing: Addressing,
442    mem_size: MemSize,
443    source: u8,
444    insn: Insn
445}
446
447impl<'i> Load<'i> {
448    /// push LOAD instruction into BpfCode instruction stack
449    pub fn push(self) -> &'i mut BpfCode {
450        let mut asm = self.into_bytes();
451        self.bpf_code.instructions.append(&mut asm);
452        self.bpf_code
453    }
454}
455
456impl<'i> Instruction for Load<'i> {
457    fn opt_code_byte(&self) -> u8 {
458        let size = self.mem_size as u8;
459        let addressing = self.addressing as u8;
460        addressing | size | self.source
461    }
462
463    fn get_insn_mut(&mut self) -> &mut Insn {
464        &mut self.insn
465    }
466
467    fn get_insn(&self) -> &Insn {
468        &self.insn
469    }
470}
471
472/// struct representation of STORE instructions
473pub struct Store<'i> {
474    bpf_code: &'i mut BpfCode,
475    mem_size: MemSize,
476    source: u8,
477    insn: Insn
478}
479
480impl<'i> Store<'i> {
481    /// push STORE instruction into BpfCode instruction stack
482    pub fn push(self) -> &'i mut BpfCode {
483        let mut asm = self.into_bytes();
484        self.bpf_code.instructions.append(&mut asm);
485        self.bpf_code
486    }
487}
488
489impl<'i> Instruction for Store<'i> {
490    fn opt_code_byte(&self) -> u8 {
491        let size = self.mem_size as u8;
492        BPF_MEM | BPF_ST | size | self.source
493    }
494
495    fn get_insn_mut(&mut self) -> &mut Insn {
496        &mut self.insn
497    }
498
499    fn get_insn(&self) -> &Insn {
500        &self.insn
501    }
502}
503
504#[derive(Copy, Clone)]
505/// Memory size for LOAD and STORE instructions
506pub enum MemSize {
507    /// 8-bit size
508    Byte = BPF_B as isize,
509    /// 16-bit size
510    HalfWord = BPF_H as isize,
511    /// 32-bit size
512    Word = BPF_W as isize,
513    /// 64-bit size
514    DoubleWord = BPF_DW as isize
515}
516
517#[derive(Copy, Clone)]
518enum Addressing {
519    Imm = BPF_IMM as isize,
520    Abs = BPF_ABS as isize,
521    Ind = BPF_IND as isize,
522    Mem = BPF_MEM as isize
523}
524
525/// struct representation of JMP instructions
526pub struct Jump<'i> {
527    bpf_code: &'i mut BpfCode,
528    cond: Cond,
529    src_bit: Source,
530    insn: Insn
531}
532
533impl<'i> Jump<'i> {
534    /// push JMP instruction into BpfCode instruction stack
535    pub fn push(self) -> &'i mut BpfCode {
536        let mut asm = self.into_bytes();
537        self.bpf_code.instructions.append(&mut asm);
538        self.bpf_code
539    }
540}
541
542impl<'i> Instruction for Jump<'i> {
543    fn opt_code_byte(&self) -> u8 {
544        let cmp: u8 = self.cond as u8;
545        let src_bit = self.src_bit as u8;
546        cmp | src_bit | BPF_JMP
547    }
548
549    fn get_insn_mut(&mut self) -> &mut Insn {
550        &mut self.insn
551    }
552
553    fn get_insn(&self) -> &Insn {
554        &self.insn
555    }
556}
557
558#[derive(Copy, Clone, PartialEq, Eq)]
559/// Conditions for JMP instructions
560pub enum Cond {
561    /// Absolute or unconditional
562    Abs = BPF_JA as isize,
563    /// Jump if `==`
564    Equals = BPF_JEQ as isize,
565    /// Jump if `>`
566    Greater = BPF_JGT as isize,
567    /// Jump if `>=`
568    GreaterEquals = BPF_JGE as isize,
569    /// Jump if `<`
570    Lower = BPF_JLT as isize,
571    /// Jump if `<=`
572    LowerEquals = BPF_JLE as isize,
573    /// Jump if `src` & `dst`
574    BitAnd = BPF_JSET as isize,
575    /// Jump if `!=`
576    NotEquals = BPF_JNE as isize,
577    /// Jump if `>` (signed)
578    GreaterSigned = BPF_JSGT as isize,
579    /// Jump if `>=` (signed)
580    GreaterEqualsSigned = BPF_JSGE as isize,
581    /// Jump if `<` (signed)
582    LowerSigned = BPF_JSLT as isize,
583    /// Jump if `<=` (signed)
584    LowerEqualsSigned = BPF_JSLE as isize
585}
586
587/// struct representation of CALL instruction
588pub struct FunctionCall<'i> {
589    bpf_code: &'i mut BpfCode,
590    insn: Insn
591}
592
593impl<'i> FunctionCall<'i> {
594    /// push CALL instruction into BpfCode instruction stack
595    pub fn push(self) -> &'i mut BpfCode {
596        let mut asm = self.into_bytes();
597        self.bpf_code.instructions.append(&mut asm);
598        self.bpf_code
599    }
600}
601
602impl<'i> Instruction for FunctionCall<'i> {
603    fn opt_code_byte(&self) -> u8 {
604        BPF_CALL | BPF_JMP
605    }
606
607    fn get_insn_mut(&mut self) -> &mut Insn {
608        &mut self.insn
609    }
610
611    fn get_insn(&self) -> &Insn {
612        &self.insn
613    }
614}
615
616/// struct representation of EXIT instruction
617pub struct Exit<'i> {
618    bpf_code: &'i mut BpfCode,
619    insn: Insn
620}
621
622impl<'i> Exit<'i> {
623    /// push EXIT instruction into BpfCode instruction stack
624    pub fn push(self) -> &'i mut BpfCode {
625        let mut asm = self.into_bytes();
626        self.bpf_code.instructions.append(&mut asm);
627        self.bpf_code
628    }
629}
630
631impl<'i> Instruction for Exit<'i> {
632    fn opt_code_byte(&self) -> u8 {
633        BPF_EXIT | BPF_JMP
634    }
635
636    fn get_insn_mut(&mut self) -> &mut Insn {
637        &mut self.insn
638    }
639
640    fn get_insn(&self) -> &Insn {
641        &self.insn
642    }
643}
644
645#[cfg(test)]
646mod tests {
647    #[cfg(test)]
648    mod special {
649        use super::super::*;
650
651        #[test]
652        fn call_immediate() {
653            let mut program = BpfCode::new();
654            program.call().set_imm(0x11_22_33_44).push();
655
656            assert_eq!(program.into_bytes(), &[0x85, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]);
657        }
658
659        #[test]
660        fn exit_operation() {
661            let mut program = BpfCode::new();
662            program.exit().push();
663
664            assert_eq!(program.into_bytes(), &[0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
665        }
666    }
667
668    #[cfg(test)]
669    mod jump_instructions {
670        #[cfg(test)]
671        mod register {
672            use super::super::super::*;
673
674            #[test]
675            fn jump_on_dst_equals_src() {
676                let mut program = BpfCode::new();
677                program.jump_conditional(Cond::Equals, Source::Reg).set_dst(0x01).set_src(0x02).push();
678
679                assert_eq!(program.into_bytes(), &[0x1d, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
680            }
681
682            #[test]
683            fn jump_on_dst_greater_than_src() {
684                let mut program = BpfCode::new();
685                program.jump_conditional(Cond::Greater, Source::Reg).set_dst(0x03).set_src(0x02).push();
686
687                assert_eq!(program.into_bytes(), &[0x2d, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
688            }
689
690            #[test]
691            fn jump_on_dst_greater_or_equals_to_src() {
692                let mut program = BpfCode::new();
693                program.jump_conditional(Cond::GreaterEquals, Source::Reg).set_dst(0x04).set_src(0x01).push();
694
695                assert_eq!(program.into_bytes(), &[0x3d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
696            }
697
698            #[test]
699            fn jump_on_dst_lower_than_src() {
700                let mut program = BpfCode::new();
701                program.jump_conditional(Cond::Lower, Source::Reg).set_dst(0x03).set_src(0x02).push();
702
703                assert_eq!(program.into_bytes(), &[0xad, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
704            }
705
706            #[test]
707            fn jump_on_dst_lower_or_equals_to_src() {
708                let mut program = BpfCode::new();
709                program.jump_conditional(Cond::LowerEquals, Source::Reg).set_dst(0x04).set_src(0x01).push();
710
711                assert_eq!(program.into_bytes(), &[0xbd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
712            }
713
714            #[test]
715            fn jump_on_dst_bit_and_with_src_not_equal_zero() {
716                let mut program = BpfCode::new();
717                program.jump_conditional(Cond::BitAnd, Source::Reg).set_dst(0x05).set_src(0x02).push();
718
719                assert_eq!(program.into_bytes(), &[0x4d, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
720            }
721
722            #[test]
723            fn jump_on_dst_not_equals_src() {
724                let mut program = BpfCode::new();
725                program.jump_conditional(Cond::NotEquals, Source::Reg).set_dst(0x03).set_src(0x05).push();
726
727                assert_eq!(program.into_bytes(), &[0x5d, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
728            }
729
730            #[test]
731            fn jump_on_dst_greater_than_src_signed() {
732                let mut program = BpfCode::new();
733                program.jump_conditional(Cond::GreaterSigned, Source::Reg).set_dst(0x04).set_src(0x01).push();
734
735                assert_eq!(program.into_bytes(), &[0x6d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
736            }
737
738            #[test]
739            fn jump_on_dst_greater_or_equals_src_signed() {
740                let mut program = BpfCode::new();
741                program.jump_conditional(Cond::GreaterEqualsSigned, Source::Reg).set_dst(0x01).set_src(0x03).push();
742
743                assert_eq!(program.into_bytes(), &[0x7d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
744            }
745
746            #[test]
747            fn jump_on_dst_lower_than_src_signed() {
748                let mut program = BpfCode::new();
749                program.jump_conditional(Cond::LowerSigned, Source::Reg).set_dst(0x04).set_src(0x01).push();
750
751                assert_eq!(program.into_bytes(), &[0xcd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
752            }
753
754            #[test]
755            fn jump_on_dst_lower_or_equals_src_signed() {
756                let mut program = BpfCode::new();
757                program.jump_conditional(Cond::LowerEqualsSigned, Source::Reg).set_dst(0x01).set_src(0x03).push();
758
759                assert_eq!(program.into_bytes(), &[0xdd, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
760            }
761        }
762
763        #[cfg(test)]
764        mod immediate {
765            use super::super::super::*;
766
767            #[test]
768            fn jump_to_label() {
769                let mut program = BpfCode::new();
770                program.jump_unconditional().set_off(0x00_11).push();
771
772                assert_eq!(program.into_bytes(), &[0x05, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]);
773            }
774
775            #[test]
776            fn jump_on_dst_equals_const() {
777                let mut program = BpfCode::new();
778                program.jump_conditional(Cond::Equals, Source::Imm).set_dst(0x01).set_imm(0x00_11_22_33).push();
779
780                assert_eq!(program.into_bytes(), &[0x15, 0x01, 0x00, 0x00, 0x33, 0x22, 0x11, 0x00]);
781            }
782
783            #[test]
784            fn jump_on_dst_greater_than_const() {
785                let mut program = BpfCode::new();
786                program.jump_conditional(Cond::Greater, Source::Imm).set_dst(0x02).set_imm(0x00_11_00_11).push();
787
788                assert_eq!(program.into_bytes(), &[0x25, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]);
789            }
790
791            #[test]
792            fn jump_on_dst_greater_or_equals_to_const() {
793                let mut program = BpfCode::new();
794                program.jump_conditional(Cond::GreaterEquals, Source::Imm).set_dst(0x04).set_imm(0x00_22_11_00).push();
795
796                assert_eq!(program.into_bytes(), &[0x35, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]);
797            }
798
799            #[test]
800            fn jump_on_dst_lower_than_const() {
801                let mut program = BpfCode::new();
802                program.jump_conditional(Cond::Lower, Source::Imm).set_dst(0x02).set_imm(0x00_11_00_11).push();
803
804                assert_eq!(program.into_bytes(), &[0xa5, 0x02, 0x00, 0x00, 0x11, 0x00, 0x11, 0x00]);
805            }
806
807            #[test]
808            fn jump_on_dst_lower_or_equals_to_const() {
809                let mut program = BpfCode::new();
810                program.jump_conditional(Cond::LowerEquals, Source::Imm).set_dst(0x04).set_imm(0x00_22_11_00).push();
811
812                assert_eq!(program.into_bytes(), &[0xb5, 0x04, 0x00, 0x00, 0x00, 0x11, 0x22, 0x00]);
813            }
814
815            #[test]
816            fn jump_on_dst_bit_and_with_const_not_equal_zero() {
817                let mut program = BpfCode::new();
818                program.jump_conditional(Cond::BitAnd, Source::Imm).set_dst(0x05).push();
819
820                assert_eq!(program.into_bytes(), &[0x45, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
821            }
822
823            #[test]
824            fn jump_on_dst_not_equals_const() {
825                let mut program = BpfCode::new();
826                program.jump_conditional(Cond::NotEquals, Source::Imm).set_dst(0x03).push();
827
828                assert_eq!(program.into_bytes(), &[0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
829            }
830
831            #[test]
832            fn jump_on_dst_greater_than_const_signed() {
833                let mut program = BpfCode::new();
834                program.jump_conditional(Cond::GreaterSigned, Source::Imm).set_dst(0x04).push();
835
836                assert_eq!(program.into_bytes(), &[0x65, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
837            }
838
839            #[test]
840            fn jump_on_dst_greater_or_equals_src_signed() {
841                let mut program = BpfCode::new();
842                program.jump_conditional(Cond::GreaterEqualsSigned, Source::Imm).set_dst(0x01).push();
843
844                assert_eq!(program.into_bytes(), &[0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
845            }
846
847            #[test]
848            fn jump_on_dst_lower_than_const_signed() {
849                let mut program = BpfCode::new();
850                program.jump_conditional(Cond::LowerSigned, Source::Imm).set_dst(0x04).push();
851
852                assert_eq!(program.into_bytes(), &[0xc5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
853            }
854
855            #[test]
856            fn jump_on_dst_lower_or_equals_src_signed() {
857                let mut program = BpfCode::new();
858                program.jump_conditional(Cond::LowerEqualsSigned, Source::Imm).set_dst(0x01).push();
859
860                assert_eq!(program.into_bytes(), &[0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
861            }
862        }
863    }
864
865    #[cfg(test)]
866    mod store_instructions {
867        use super::super::*;
868
869        #[test]
870        fn store_word_from_dst_into_immediate_address() {
871            let mut program = BpfCode::new();
872            program.store(MemSize::Word).set_dst(0x01).set_off(0x00_11).set_imm(0x11_22_33_44).push();
873
874            assert_eq!(program.into_bytes(), &[0x62, 0x01, 0x11, 0x00, 0x44, 0x33, 0x22, 0x11]);
875        }
876
877        #[test]
878        fn store_half_word_from_dst_into_immediate_address() {
879            let mut program = BpfCode::new();
880            program.store(MemSize::HalfWord).set_dst(0x02).set_off(0x11_22).push();
881
882            assert_eq!(program.into_bytes(), &[0x6a, 0x02, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]);
883        }
884
885        #[test]
886        fn store_byte_from_dst_into_immediate_address() {
887            let mut program = BpfCode::new();
888            program.store(MemSize::Byte).push();
889
890            assert_eq!(program.into_bytes(), &[0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
891        }
892
893        #[test]
894        fn store_double_word_from_dst_into_immediate_address() {
895            let mut program = BpfCode::new();
896            program.store(MemSize::DoubleWord).push();
897
898            assert_eq!(program.into_bytes(), &[0x7a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
899        }
900
901        #[test]
902        fn store_word_from_dst_into_src_address() {
903            let mut program = BpfCode::new();
904            program.store_x(MemSize::Word).set_dst(0x01).set_src(0x02).push();
905
906            assert_eq!(program.into_bytes(), &[0x63, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
907        }
908
909        #[test]
910        fn store_half_word_from_dst_into_src_address() {
911            let mut program = BpfCode::new();
912            program.store_x(MemSize::HalfWord).push();
913
914            assert_eq!(program.into_bytes(), &[0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
915        }
916
917        #[test]
918        fn store_byte_from_dst_into_src_address() {
919            let mut program = BpfCode::new();
920            program.store_x(MemSize::Byte).push();
921
922            assert_eq!(program.into_bytes(), &[0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
923        }
924
925        #[test]
926        fn store_double_word_from_dst_into_src_address() {
927            let mut program = BpfCode::new();
928            program.store_x(MemSize::DoubleWord).push();
929
930            assert_eq!(program.into_bytes(), &[0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
931        }
932    }
933
934    #[cfg(test)]
935    mod load_instructions {
936        #[cfg(test)]
937        mod register {
938            use super::super::super::*;
939
940            #[test]
941            fn load_word_from_set_src_with_offset() {
942                let mut program = BpfCode::new();
943                program.load_x(MemSize::Word).set_dst(0x01).set_src(0x02).set_off(0x00_02).push();
944
945                assert_eq!(program.into_bytes(), &[0x61, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00]);
946            }
947
948            #[test]
949            fn load_half_word_from_set_src_with_offset() {
950                let mut program = BpfCode::new();
951                program.load_x(MemSize::HalfWord).set_dst(0x02).set_src(0x01).set_off(0x11_22).push();
952
953                assert_eq!(program.into_bytes(), &[0x69, 0x12, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00]);
954            }
955
956            #[test]
957            fn load_byte_from_set_src_with_offset() {
958                let mut program = BpfCode::new();
959                program.load_x(MemSize::Byte).set_dst(0x01).set_src(0x04).set_off(0x00_11).push();
960
961                assert_eq!(program.into_bytes(), &[0x71, 0x41, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00]);
962            }
963
964            #[test]
965            fn load_double_word_from_set_src_with_offset() {
966                let mut program = BpfCode::new();
967                program.load_x(MemSize::DoubleWord).set_dst(0x04).set_src(0x05).set_off(0x44_55).push();
968
969                assert_eq!(program.into_bytes(), &[0x79, 0x54, 0x55, 0x44, 0x00, 0x00, 0x00, 0x00]);
970            }
971        }
972
973        #[cfg(test)]
974        mod immediate {
975            use super::super::super::*;
976
977            #[test]
978            fn load_double_word() {
979                let mut program = BpfCode::new();
980                program.load(MemSize::DoubleWord).set_dst(0x01).set_imm(0x00_01_02_03).push();
981
982                assert_eq!(program.into_bytes(), &[0x18, 0x01, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]);
983            }
984
985            #[test]
986            fn load_abs_word() {
987                let mut program = BpfCode::new();
988                program.load_abs(MemSize::Word).push();
989
990                assert_eq!(program.into_bytes(), &[0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
991            }
992
993            #[test]
994            fn load_abs_half_word() {
995                let mut program = BpfCode::new();
996                program.load_abs(MemSize::HalfWord).set_dst(0x05).push();
997
998                assert_eq!(program.into_bytes(), &[0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
999            }
1000
1001            #[test]
1002            fn load_abs_byte() {
1003                let mut program = BpfCode::new();
1004                program.load_abs(MemSize::Byte).set_dst(0x01).push();
1005
1006                assert_eq!(program.into_bytes(), &[0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1007            }
1008
1009            #[test]
1010            fn load_abs_double_word() {
1011                let mut program = BpfCode::new();
1012                program.load_abs(MemSize::DoubleWord).set_dst(0x01).set_imm(0x01_02_03_04).push();
1013
1014                assert_eq!(program.into_bytes(), &[0x38, 0x01, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]);
1015            }
1016
1017            #[test]
1018            fn load_indirect_word() {
1019                let mut program = BpfCode::new();
1020                program.load_ind(MemSize::Word).push();
1021
1022                assert_eq!(program.into_bytes(), &[0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1023            }
1024
1025            #[test]
1026            fn load_indirect_half_word() {
1027                let mut program = BpfCode::new();
1028                program.load_ind(MemSize::HalfWord).push();
1029
1030                assert_eq!(program.into_bytes(), &[0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1031            }
1032
1033            #[test]
1034            fn load_indirect_byte() {
1035                let mut program = BpfCode::new();
1036                program.load_ind(MemSize::Byte).push();
1037
1038                assert_eq!(program.into_bytes(), &[0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1039            }
1040
1041            #[test]
1042            fn load_indirect_double_word() {
1043                let mut program = BpfCode::new();
1044                program.load_ind(MemSize::DoubleWord).push();
1045
1046                assert_eq!(program.into_bytes(), &[0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1047            }
1048        }
1049    }
1050
1051    #[cfg(test)]
1052    mod byte_swap_instructions {
1053        use super::super::*;
1054
1055        #[test]
1056        fn convert_host_to_little_endian_16bits() {
1057            let mut program = BpfCode::new();
1058            program.swap_bytes(Endian::Little).set_dst(0x01).set_imm(0x00_00_00_10).push();
1059
1060            assert_eq!(program.into_bytes(), &[0xd4, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]);
1061        }
1062
1063        #[test]
1064        fn convert_host_to_little_endian_32bits() {
1065            let mut program = BpfCode::new();
1066            program.swap_bytes(Endian::Little).set_dst(0x02).set_imm(0x00_00_00_20).push();
1067
1068            assert_eq!(program.into_bytes(), &[0xd4, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]);
1069        }
1070
1071        #[test]
1072        fn convert_host_to_little_endian_64bit() {
1073            let mut program = BpfCode::new();
1074            program.swap_bytes(Endian::Little).set_dst(0x03).set_imm(0x00_00_00_40).push();
1075
1076            assert_eq!(program.into_bytes(), &[0xd4, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]);
1077        }
1078
1079        #[test]
1080        fn convert_host_to_big_endian_16bits() {
1081            let mut program = BpfCode::new();
1082            program.swap_bytes(Endian::Big).set_dst(0x01).set_imm(0x00_00_00_10).push();
1083
1084            assert_eq!(program.into_bytes(), &[0xdc, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00]);
1085        }
1086
1087        #[test]
1088        fn convert_host_to_big_endian_32bits() {
1089            let mut program = BpfCode::new();
1090            program.swap_bytes(Endian::Big).set_dst(0x02).set_imm(0x00_00_00_20).push();
1091
1092            assert_eq!(program.into_bytes(), &[0xdc, 0x02, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00]);
1093        }
1094
1095        #[test]
1096        fn convert_host_to_big_endian_64bit() {
1097            let mut program = BpfCode::new();
1098            program.swap_bytes(Endian::Big).set_dst(0x03).set_imm(0x00_00_00_40).push();
1099
1100            assert_eq!(program.into_bytes(), &[0xdc, 0x03, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00]);
1101        }
1102    }
1103
1104    #[cfg(test)]
1105    mod moves_instructions {
1106        #[cfg(test)]
1107        mod arch_x64 {
1108            #[cfg(test)]
1109            mod immediate {
1110                use super::super::super::super::*;
1111
1112                #[test]
1113                fn move_and_add_const_to_register() {
1114                    let mut program = BpfCode::new();
1115                    program.add(Source::Imm, Arch::X64).set_dst(0x02).set_imm(0x01_02_03_04).push();
1116
1117                    assert_eq!(program.into_bytes(), &[0x07, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]);
1118                }
1119
1120                #[test]
1121                fn move_sub_const_to_register() {
1122                    let mut program = BpfCode::new();
1123                    program.sub(Source::Imm, Arch::X64).set_dst(0x04).set_imm(0x00_01_02_03).push();
1124
1125                    assert_eq!(program.into_bytes(), &[0x17, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]);
1126                }
1127
1128                #[test]
1129                fn move_mul_const_to_register() {
1130                    let mut program = BpfCode::new();
1131                    program.mul(Source::Imm, Arch::X64).set_dst(0x05).set_imm(0x04_03_02_01).push();
1132
1133                    assert_eq!(program.into_bytes(), &[0x27, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]);
1134                }
1135
1136                #[test]
1137                fn move_div_constant_to_register() {
1138                    let mut program = BpfCode::new();
1139                    program.div(Source::Imm, Arch::X64).set_dst(0x02).set_imm(0x00_ff_00_ff).push();
1140
1141                    assert_eq!(program.into_bytes(), &[0x37, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]);
1142                }
1143
1144                #[test]
1145                fn move_bit_or_const_to_register() {
1146                    let mut program = BpfCode::new();
1147                    program.bit_or(Source::Imm, Arch::X64).set_dst(0x02).set_imm(0x00_11_00_22).push();
1148
1149                    assert_eq!(program.into_bytes(), &[0x47, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]);
1150                }
1151
1152                #[test]
1153                fn move_bit_and_const_to_register() {
1154                    let mut program = BpfCode::new();
1155                    program.bit_and(Source::Imm, Arch::X64).set_dst(0x02).set_imm(0x11_22_33_44).push();
1156
1157                    assert_eq!(program.into_bytes(), &[0x57, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]);
1158                }
1159
1160                #[test]
1161                fn move_left_shift_const_to_register() {
1162                    let mut program = BpfCode::new();
1163                    program.left_shift(Source::Imm, Arch::X64).set_dst(0x01).push();
1164
1165                    assert_eq!(program.into_bytes(), &[0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1166                }
1167
1168                #[test]
1169                fn move_logical_right_shift_const_to_register() {
1170                    let mut program = BpfCode::new();
1171                    program.right_shift(Source::Imm, Arch::X64).set_dst(0x01).push();
1172
1173                    assert_eq!(program.into_bytes(), &[0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1174                }
1175
1176                #[test]
1177                fn move_negate_register() {
1178                    let mut program = BpfCode::new();
1179                    program.negate(Arch::X64).set_dst(0x02).push();
1180
1181                    assert_eq!(program.into_bytes(), &[0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1182                }
1183
1184                #[test]
1185                fn move_mod_const_to_register() {
1186                    let mut program = BpfCode::new();
1187                    program.modulo(Source::Imm, Arch::X64).set_dst(0x02).push();
1188
1189                    assert_eq!(program.into_bytes(), &[0x97, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1190                }
1191
1192                #[test]
1193                fn move_bit_xor_const_to_register() {
1194                    let mut program = BpfCode::new();
1195                    program.bit_xor(Source::Imm, Arch::X64).set_dst(0x03).push();
1196
1197                    assert_eq!(program.into_bytes(), &[0xa7, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1198                }
1199
1200                #[test]
1201                fn move_const_to_register() {
1202                    let mut program = BpfCode::new();
1203                    program.mov(Source::Imm, Arch::X64).set_dst(0x01).set_imm(0x00_00_00_FF).push();
1204
1205                    assert_eq!(program.into_bytes(), &[0xb7, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]);
1206                }
1207
1208                #[test]
1209                fn move_signed_right_shift_const_to_register() {
1210                    let mut program = BpfCode::new();
1211                    program.signed_right_shift(Source::Imm, Arch::X64).set_dst(0x05).push();
1212
1213                    assert_eq!(program.into_bytes(), &[0xc7, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1214                }
1215            }
1216
1217            #[cfg(test)]
1218            mod register {
1219                use super::super::super::super::*;
1220
1221                #[test]
1222                fn move_and_add_from_register() {
1223                    let mut program = BpfCode::new();
1224                    program.add(Source::Reg, Arch::X64).set_dst(0x03).set_src(0x02).push();
1225
1226                    assert_eq!(program.into_bytes(), &[0x0f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1227                }
1228
1229                #[test]
1230                fn move_sub_from_register_to_register() {
1231                    let mut program = BpfCode::new();
1232                    program.sub(Source::Reg, Arch::X64).set_dst(0x03).set_src(0x04).push();
1233
1234                    assert_eq!(program.into_bytes(), &[0x1f, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1235                }
1236
1237                #[test]
1238                fn move_mul_from_register_to_register() {
1239                    let mut program = BpfCode::new();
1240                    program.mul(Source::Reg, Arch::X64).set_dst(0x04).set_src(0x03).push();
1241
1242                    assert_eq!(program.into_bytes(), &[0x2f, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1243                }
1244
1245                #[test]
1246                fn move_div_from_register_to_register() {
1247                    let mut program = BpfCode::new();
1248                    program.div(Source::Reg, Arch::X64).set_dst(0x01).set_src(0x00).push();
1249
1250                    assert_eq!(program.into_bytes(), &[0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1251                }
1252
1253                #[test]
1254                fn move_bit_or_from_register_to_register() {
1255                    let mut program = BpfCode::new();
1256                    program.bit_or(Source::Reg, Arch::X64).set_dst(0x03).set_src(0x01).push();
1257
1258                    assert_eq!(program.into_bytes(), &[0x4f, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1259                }
1260
1261                #[test]
1262                fn move_bit_and_from_register_to_register() {
1263                    let mut program = BpfCode::new();
1264                    program.bit_and(Source::Reg, Arch::X64).set_dst(0x03).set_src(0x02).push();
1265
1266                    assert_eq!(program.into_bytes(), &[0x5f, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1267                }
1268
1269                #[test]
1270                fn move_left_shift_from_register_to_register() {
1271                    let mut program = BpfCode::new();
1272                    program.left_shift(Source::Reg, Arch::X64).set_dst(0x02).set_src(0x03).push();
1273
1274                    assert_eq!(program.into_bytes(), &[0x6f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1275                }
1276
1277                #[test]
1278                fn move_logical_right_shift_from_register_to_register() {
1279                    let mut program = BpfCode::new();
1280                    program.right_shift(Source::Reg, Arch::X64).set_dst(0x02).set_src(0x04).push();
1281
1282                    assert_eq!(program.into_bytes(), &[0x7f, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1283                }
1284
1285                #[test]
1286                fn move_mod_from_register_to_register() {
1287                    let mut program = BpfCode::new();
1288                    program.modulo(Source::Reg, Arch::X64).set_dst(0x01).set_src(0x02).push();
1289
1290                    assert_eq!(program.into_bytes(), &[0x9f, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1291                }
1292
1293                #[test]
1294                fn move_bit_xor_from_register_to_register() {
1295                    let mut program = BpfCode::new();
1296                    program.bit_xor(Source::Reg, Arch::X64).set_dst(0x02).set_src(0x04).push();
1297
1298                    assert_eq!(program.into_bytes(), &[0xaf, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1299                }
1300
1301                #[test]
1302                fn move_from_register_to_another_register() {
1303                    let mut program = BpfCode::new();
1304                    program.mov(Source::Reg, Arch::X64).set_src(0x01).push();
1305
1306                    assert_eq!(program.into_bytes(), &[0xbf, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1307                }
1308
1309                #[test]
1310                fn move_signed_right_shift_from_register_to_register() {
1311                    let mut program = BpfCode::new();
1312                    program.signed_right_shift(Source::Reg, Arch::X64).set_dst(0x02).set_src(0x03).push();
1313
1314                    assert_eq!(program.into_bytes(), &[0xcf, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1315                }
1316            }
1317        }
1318
1319        #[cfg(test)]
1320        mod arch_x32 {
1321            #[cfg(test)]
1322            mod immediate {
1323                use super::super::super::super::*;
1324
1325                #[test]
1326                fn move_and_add_const_to_register() {
1327                    let mut program = BpfCode::new();
1328                    program.add(Source::Imm, Arch::X32).set_dst(0x02).set_imm(0x01_02_03_04).push();
1329
1330                    assert_eq!(program.into_bytes(), &[0x04, 0x02, 0x00, 0x00, 0x04, 0x03, 0x02, 0x01]);
1331                }
1332
1333                #[test]
1334                fn move_sub_const_to_register() {
1335                    let mut program = BpfCode::new();
1336                    program.sub(Source::Imm, Arch::X32).set_dst(0x04).set_imm(0x00_01_02_03).push();
1337
1338                    assert_eq!(program.into_bytes(), &[0x14, 0x04, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00]);
1339                }
1340
1341                #[test]
1342                fn move_mul_const_to_register() {
1343                    let mut program = BpfCode::new();
1344                    program.mul(Source::Imm, Arch::X32).set_dst(0x05).set_imm(0x04_03_02_01).push();
1345
1346                    assert_eq!(program.into_bytes(), &[0x24, 0x05, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04]);
1347                }
1348
1349                #[test]
1350                fn move_div_constant_to_register() {
1351                    let mut program = BpfCode::new();
1352                    program.div(Source::Imm, Arch::X32).set_dst(0x02).set_imm(0x00_ff_00_ff).push();
1353
1354                    assert_eq!(program.into_bytes(), &[0x34, 0x02, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00]);
1355                }
1356
1357                #[test]
1358                fn move_bit_or_const_to_register() {
1359                    let mut program = BpfCode::new();
1360                    program.bit_or(Source::Imm, Arch::X32).set_dst(0x02).set_imm(0x00_11_00_22).push();
1361
1362                    assert_eq!(program.into_bytes(), &[0x44, 0x02, 0x00, 0x00, 0x22, 0x00, 0x11, 0x00]);
1363                }
1364
1365                #[test]
1366                fn move_bit_and_const_to_register() {
1367                    let mut program = BpfCode::new();
1368                    program.bit_and(Source::Imm, Arch::X32).set_dst(0x02).set_imm(0x11_22_33_44).push();
1369
1370                    assert_eq!(program.into_bytes(), &[0x54, 0x02, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11]);
1371                }
1372
1373                #[test]
1374                fn move_left_shift_const_to_register() {
1375                    let mut program = BpfCode::new();
1376                    program.left_shift(Source::Imm, Arch::X32).set_dst(0x01).push();
1377
1378                    assert_eq!(program.into_bytes(), &[0x64, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1379                }
1380
1381                #[test]
1382                fn move_logical_right_shift_const_to_register() {
1383                    let mut program = BpfCode::new();
1384                    program.right_shift(Source::Imm, Arch::X32).set_dst(0x01).push();
1385
1386                    assert_eq!(program.into_bytes(), &[0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1387                }
1388
1389                #[test]
1390                fn move_negate_register() {
1391                    let mut program = BpfCode::new();
1392                    program.negate(Arch::X32).set_dst(0x02).push();
1393
1394                    assert_eq!(program.into_bytes(), &[0x84, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1395                }
1396
1397                #[test]
1398                fn move_mod_const_to_register() {
1399                    let mut program = BpfCode::new();
1400                    program.modulo(Source::Imm, Arch::X32).set_dst(0x02).push();
1401
1402                    assert_eq!(program.into_bytes(), &[0x94, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1403                }
1404
1405                #[test]
1406                fn move_bit_xor_const_to_register() {
1407                    let mut program = BpfCode::new();
1408                    program.bit_xor(Source::Imm, Arch::X32).set_dst(0x03).push();
1409
1410                    assert_eq!(program.into_bytes(), &[0xa4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1411                }
1412
1413                #[test]
1414                fn move_const_to_register() {
1415                    let mut program = BpfCode::new();
1416                    program.mov(Source::Imm, Arch::X32).set_dst(0x01).set_imm(0x00_00_00_FF).push();
1417
1418                    assert_eq!(program.into_bytes(), &[0xb4, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00]);
1419                }
1420
1421                #[test]
1422                fn move_signed_right_shift_const_to_register() {
1423                    let mut program = BpfCode::new();
1424                    program.signed_right_shift(Source::Imm, Arch::X32).set_dst(0x05).push();
1425
1426                    assert_eq!(program.into_bytes(), &[0xc4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1427                }
1428            }
1429
1430            #[cfg(test)]
1431            mod register {
1432                use super::super::super::super::*;
1433
1434                #[test]
1435                fn move_and_add_from_register() {
1436                    let mut program = BpfCode::new();
1437                    program.add(Source::Reg, Arch::X32).set_dst(0x03).set_src(0x02).push();
1438
1439                    assert_eq!(program.into_bytes(), &[0x0c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1440                }
1441
1442                #[test]
1443                fn move_sub_from_register_to_register() {
1444                    let mut program = BpfCode::new();
1445                    program.sub(Source::Reg, Arch::X32).set_dst(0x03).set_src(0x04).push();
1446
1447                    assert_eq!(program.into_bytes(), &[0x1c, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1448                }
1449
1450                #[test]
1451                fn move_mul_from_register_to_register() {
1452                    let mut program = BpfCode::new();
1453                    program.mul(Source::Reg, Arch::X32).set_dst(0x04).set_src(0x03).push();
1454
1455                    assert_eq!(program.into_bytes(), &[0x2c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1456                }
1457
1458                #[test]
1459                fn move_div_from_register_to_register() {
1460                    let mut program = BpfCode::new();
1461                    program.div(Source::Reg, Arch::X32).set_dst(0x01).set_src(0x00).push();
1462
1463                    assert_eq!(program.into_bytes(), &[0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1464                }
1465
1466                #[test]
1467                fn move_bit_or_from_register_to_register() {
1468                    let mut program = BpfCode::new();
1469                    program.bit_or(Source::Reg, Arch::X32).set_dst(0x03).set_src(0x01).push();
1470
1471                    assert_eq!(program.into_bytes(), &[0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1472                }
1473
1474                #[test]
1475                fn move_bit_and_from_register_to_register() {
1476                    let mut program = BpfCode::new();
1477                    program.bit_and(Source::Reg, Arch::X32).set_dst(0x03).set_src(0x02).push();
1478
1479                    assert_eq!(program.into_bytes(), &[0x5c, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1480                }
1481
1482                #[test]
1483                fn move_left_shift_from_register_to_register() {
1484                    let mut program = BpfCode::new();
1485                    program.left_shift(Source::Reg, Arch::X32).set_dst(0x02).set_src(0x03).push();
1486
1487                    assert_eq!(program.into_bytes(), &[0x6c, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1488                }
1489
1490                #[test]
1491                fn move_logical_right_shift_from_register_to_register() {
1492                    let mut program = BpfCode::new();
1493                    program.right_shift(Source::Reg, Arch::X32).set_dst(0x02).set_src(0x04).push();
1494
1495                    assert_eq!(program.into_bytes(), &[0x7c, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1496                }
1497
1498                #[test]
1499                fn move_mod_from_register_to_register() {
1500                    let mut program = BpfCode::new();
1501                    program.modulo(Source::Reg, Arch::X32).set_dst(0x01).set_src(0x02).push();
1502
1503                    assert_eq!(program.into_bytes(), &[0x9c, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1504                }
1505
1506                #[test]
1507                fn move_bit_xor_from_register_to_register() {
1508                    let mut program = BpfCode::new();
1509                    program.bit_xor(Source::Reg, Arch::X32).set_dst(0x02).set_src(0x04).push();
1510
1511                    assert_eq!(program.into_bytes(), &[0xac, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1512                }
1513
1514                #[test]
1515                fn move_from_register_to_another_register() {
1516                    let mut program = BpfCode::new();
1517                    program.mov(Source::Reg, Arch::X32).set_dst(0x00).set_src(0x01).push();
1518
1519                    assert_eq!(program.into_bytes(), &[0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1520                }
1521
1522                #[test]
1523                fn move_signed_right_shift_from_register_to_register() {
1524                    let mut program = BpfCode::new();
1525                    program.signed_right_shift(Source::Reg, Arch::X32).set_dst(0x02).set_src(0x03).push();
1526
1527                    assert_eq!(program.into_bytes(), &[0xcc, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
1528                }
1529            }
1530        }
1531    }
1532
1533    #[cfg(test)]
1534    mod programs {
1535        use super::super::*;
1536
1537        #[test]
1538        fn example_from_assembler() {
1539            let mut program = BpfCode::new();
1540            program.add(Source::Imm, Arch::X64).set_dst(1).set_imm(0x605).push()
1541                   .mov(Source::Imm, Arch::X64).set_dst(2).set_imm(0x32).push()
1542                   .mov(Source::Reg, Arch::X64).set_src(0).set_dst(1).push()
1543                   .swap_bytes(Endian::Big).set_dst(0).set_imm(0x10).push()
1544                   .negate(Arch::X64).set_dst(2).push()
1545                   .exit().push();
1546
1547            let bytecode = program.into_bytes();
1548            let ref_prog = &[
1549                0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
1550                0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
1551                0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1552                0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
1553                0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1554                0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
1555            ];
1556            // cargo says: "`[{integer}; 48]` cannot be formatted using `{:?}`
1557            //              because it doesn't implement `std::fmt::Debug`"
1558            // So let's check in two steps.
1559            assert_eq!(bytecode[..32], ref_prog[..32]);
1560            assert_eq!(bytecode[33..], ref_prog[33..]);
1561        }
1562    }
1563}