solana_sbpf/
insn_builder.rs

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