bpf_ins/
instruction.rs

1use crate::error::{Error, Result};
2
3/// Enum for each opcode defined in the spec. This is the 3 LSB
4/// of the first byte in the instruction.
5#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
6#[repr(u8)]
7pub enum OpcodeClass {
8    Load = 0x00,         // non-standard load
9    LoadReg = 0x01,      // load into register
10    Store = 0x02,        // store from immediate
11    StoreReg = 0x03,     // store from register
12    Arithmetic = 0x04,   // 32-bit arithmetic
13    Jump = 0x05,         // 64-bit jumps
14    Jump32 = 0x06,       // 32-bit jumps
15    Arithmetic64 = 0x07, // 64-bit arithmetic
16}
17
18impl OpcodeClass {
19    const MASK: u64 = 0x07;
20
21    /// Creates an instance of this object from a full, raw instruction.
22    fn from_raw_instruction(instruction: u64) -> Self {
23        let class = (instruction & Self::MASK) as u8;
24        match class {
25            x if x == Self::Load as u8 => Self::Load,
26            x if x == Self::LoadReg as u8 => Self::LoadReg,
27            x if x == Self::Store as u8 => Self::Store,
28            x if x == Self::StoreReg as u8 => Self::StoreReg,
29            x if x == Self::Arithmetic as u8 => Self::Arithmetic,
30            x if x == Self::Jump as u8 => Self::Jump,
31            x if x == Self::Jump32 as u8 => Self::Jump32,
32            x if x == Self::Arithmetic64 as u8 => Self::Arithmetic64,
33            _ => unreachable!("Mask or match arms have been broken"),
34        }
35    }
36
37    /// Returns the 3 bits that makes up this value in the opcode byte.
38    fn as_opcode(&self) -> u8 {
39        *self as u8
40    }
41}
42
43/// The source operand portion of the instruction's opcode.
44#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
45pub enum SourceOperand {
46    Immediate = 0x00, // use immediate for jump/arithmetic
47    Register = 0x08,  // use source register for jump/arithmetic
48}
49
50impl SourceOperand {
51    const MASK: u64 = 0x08;
52
53    /// Creates an instance of this object from a full, raw instruction.
54    fn from_raw_instruction(instruction: u64) -> Self {
55        if instruction & Self::MASK == Self::MASK {
56            Self::Register
57        } else {
58            Self::Immediate
59        }
60    }
61
62    /// Returns the bit that makes up this value in the opcode byte.
63    fn as_opcode(&self) -> u8 {
64        match self {
65            Self::Register => Self::Register as u8,
66            Self::Immediate => Self::Immediate as u8,
67        }
68    }
69}
70
71/// The arithmetic portion of the instruction's opcode.
72#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
73pub enum ArithmeticOperation {
74    Add = 0x00, // dst += src
75    Sub = 0x10, // dst -= src
76    Mul = 0x20, // dst *= src
77    Div = 0x30, // dst /= src
78    Or = 0x40,  // dst |= src
79    And = 0x50, // dst &= src
80    Lhs = 0x60, // dst <<= src
81    Rhs = 0x70, // dst >>= src
82    Neg = 0x80, // dst = ~src
83    Mod = 0x90, // dst %= src
84    Xor = 0xa0, // dst ^= src
85    Mov = 0xb0, // dst = src
86    Ash = 0xc0, // dst s>> src
87    End = 0xd0, // dst = swap(dst)
88}
89
90impl ArithmeticOperation {
91    const MASK: u64 = 0xf0;
92
93    /// Creates an instance of this object from a full, raw instruction.
94    fn from_raw_instruction(instruction: u64) -> Result<Self> {
95        let operation = (instruction & Self::MASK) as u8;
96        match operation {
97            x if x == Self::Add as u8 => Ok(Self::Add),
98            x if x == Self::Sub as u8 => Ok(Self::Sub),
99            x if x == Self::Mul as u8 => Ok(Self::Mul),
100            x if x == Self::Div as u8 => Ok(Self::Div),
101            x if x == Self::Or as u8 => Ok(Self::Or),
102            x if x == Self::And as u8 => Ok(Self::And),
103            x if x == Self::Lhs as u8 => Ok(Self::Lhs),
104            x if x == Self::Rhs as u8 => Ok(Self::Rhs),
105            x if x == Self::Neg as u8 => Ok(Self::Neg),
106            x if x == Self::Mod as u8 => Ok(Self::Mod),
107            x if x == Self::Xor as u8 => Ok(Self::Xor),
108            x if x == Self::Mov as u8 => Ok(Self::Mov),
109            x if x == Self::Ash as u8 => Ok(Self::Ash),
110            x if x == Self::End as u8 => Ok(Self::End),
111            x => Err(Error::InvalidArithmeticOperation(x)),
112        }
113    }
114
115    /// Returns the 4 bits that makes up this value in the opcode byte.
116    fn as_opcode(&self) -> u8 {
117        match self {
118            Self::Add => Self::Add as u8,
119            Self::Sub => Self::Sub as u8,
120            Self::Mul => Self::Mul as u8,
121            Self::Div => Self::Div as u8,
122            Self::Or => Self::Or as u8,
123            Self::And => Self::And as u8,
124            Self::Lhs => Self::Lhs as u8,
125            Self::Rhs => Self::Rhs as u8,
126            Self::Neg => Self::Neg as u8,
127            Self::Mod => Self::Mod as u8,
128            Self::Xor => Self::Xor as u8,
129            Self::Mov => Self::Mov as u8,
130            Self::Ash => Self::Ash as u8,
131            Self::End => Self::End as u8,
132        }
133    }
134}
135
136/// The swap order portion of the instruction's opcode.
137#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
138pub enum SwapOrder {
139    #[default]
140    Little = 0x00,
141    Big = 0x08,
142}
143
144impl SwapOrder {
145    const MASK: u64 = 0x08;
146
147    /// Creates an instance of this object from a full, raw instruction.
148    fn from_raw_instruction(instruction: u64) -> Self {
149        if instruction & Self::MASK == Self::MASK {
150            Self::Big
151        } else {
152            Self::Little
153        }
154    }
155
156    /// Returns the bit that makes up this value in the opcode byte.
157    fn as_opcode(&self) -> u8 {
158        match self {
159            Self::Big => Self::Big as u8,
160            Self::Little => Self::Little as u8,
161        }
162    }
163}
164
165/// Represents a full arithmetic opcode: class, source, operation, order.
166#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
167pub struct ArithmeticOpcode {
168    class: OpcodeClass,
169    source: SourceOperand,
170    operation: ArithmeticOperation,
171    order: SwapOrder,
172}
173
174impl ArithmeticOpcode {
175    /// Creates an instance of this object from a full, raw instruction.
176    fn from_raw_instruction(instruction: u64) -> Result<Self> {
177        let class = OpcodeClass::from_raw_instruction(instruction);
178        match class {
179            OpcodeClass::Arithmetic | OpcodeClass::Arithmetic64 => (),
180            _ => return Err(Error::InvalidOpcode(instruction as u8)),
181        }
182
183        Ok(Self {
184            class,
185            source: SourceOperand::from_raw_instruction(instruction),
186            operation: ArithmeticOperation::from_raw_instruction(instruction)?,
187            order: SwapOrder::from_raw_instruction(instruction),
188        })
189    }
190
191    /// Returns the full opcode (first byte) for this instruction.
192    fn as_opcode(&self) -> u8 {
193        self.class.as_opcode()
194            | self.source.as_opcode()
195            | self.operation.as_opcode()
196            | self.order.as_opcode()
197    }
198
199    /// Returns the opcode's class.
200    ///
201    /// # Example
202    /// ```
203    /// use bpf_ins::{Instruction, Opcode, OpcodeClass, Register};
204    ///
205    /// let instruction = Instruction::addx64(Register::R1, Register::R2);
206    /// let opcode = instruction.get_opcode();
207    /// assert!(matches!(opcode, Opcode::Arithmetic(_)));
208    /// if let Opcode::Arithmetic(arithmetic) = opcode {
209    ///     assert!(matches!(arithmetic.get_class(), OpcodeClass::Arithmetic64));
210    /// }
211    /// ```
212    pub fn get_class(&self) -> &OpcodeClass {
213        &self.class
214    }
215
216    /// Returns the opcode's source operand.
217    ///
218    /// # Example
219    /// ```
220    /// use bpf_ins::{Instruction, Opcode, Register, SourceOperand};
221    ///
222    /// let instruction = Instruction::addx64(Register::R1, Register::R2);
223    /// let opcode = instruction.get_opcode();
224    /// assert!(matches!(opcode, Opcode::Arithmetic(_)));
225    /// if let Opcode::Arithmetic(arithmetic) = opcode {
226    ///     assert!(matches!(arithmetic.get_source(), SourceOperand::Register));
227    /// }
228    /// ```
229    pub fn get_source(&self) -> &SourceOperand {
230        &self.source
231    }
232
233    /// Returns the arithmetic operation.
234    ///
235    /// # Example
236    /// ```
237    /// use bpf_ins::{ArithmeticOperation, Instruction, Opcode, Register};
238    ///
239    /// let instruction = Instruction::addx64(Register::R1, Register::R2);
240    /// let opcode = instruction.get_opcode();
241    /// assert!(matches!(opcode, Opcode::Arithmetic(_)));
242    /// if let Opcode::Arithmetic(arithmetic) = opcode {
243    ///     assert!(matches!(arithmetic.get_operation(), ArithmeticOperation::Add));
244    /// }
245    /// ```
246    pub fn get_operation(&self) -> &ArithmeticOperation {
247        &self.operation
248    }
249
250    /// Returns the operation's swap order, if the operation is ArithmeticOperation::End.
251    pub fn get_order(&self) -> &SwapOrder {
252        &self.order
253    }
254}
255
256/// The jump operation portion of the instruction's opcode.
257#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
258pub enum JumpOperation {
259    Absolute = 0x00,
260    IfEqual = 0x10,
261    IfGreater = 0x20,
262    IfGreaterOrEqual = 0x30,
263    IfAnd = 0x40,
264    IfNotEqual = 0x50,
265    IfSignedGreater = 0x60,
266    IfSignedGreaterOrEqual = 0x70,
267    Call = 0x80,
268    Exit = 0x90,
269    IfLessThan = 0xa0,
270    IfLessThanOrEqual = 0xb0,
271    IfSignedLessThan = 0xc0,
272    IfSignedLessThanOrEqual = 0xd0,
273}
274
275impl JumpOperation {
276    const MASK: u64 = 0xf0;
277
278    /// Creates an instance of this object from a full, raw instruction.
279    fn from_raw_instruction(instruction: u64) -> Result<Self> {
280        let operation = (instruction & Self::MASK) as u8;
281        match operation {
282            x if x == Self::Absolute as u8 => Ok(Self::Absolute),
283            x if x == Self::IfEqual as u8 => Ok(Self::IfEqual),
284            x if x == Self::IfGreater as u8 => Ok(Self::IfGreater),
285            x if x == Self::IfGreaterOrEqual as u8 => Ok(Self::IfGreaterOrEqual),
286            x if x == Self::IfAnd as u8 => Ok(Self::IfAnd),
287            x if x == Self::IfNotEqual as u8 => Ok(Self::IfNotEqual),
288            x if x == Self::IfSignedGreater as u8 => Ok(Self::IfSignedGreater),
289            x if x == Self::IfSignedGreaterOrEqual as u8 => Ok(Self::IfSignedGreaterOrEqual),
290            x if x == Self::Call as u8 => Ok(Self::Call),
291            x if x == Self::Exit as u8 => Ok(Self::Exit),
292            x if x == Self::IfLessThan as u8 => Ok(Self::IfLessThan),
293            x if x == Self::IfLessThanOrEqual as u8 => Ok(Self::IfLessThanOrEqual),
294            x if x == Self::IfSignedLessThan as u8 => Ok(Self::IfSignedLessThan),
295            x if x == Self::IfSignedLessThanOrEqual as u8 => Ok(Self::IfSignedLessThanOrEqual),
296            x => Err(Error::InvalidJumpOperation(x)),
297        }
298    }
299
300    /// Returns the 4 bits that makes up this value in the opcode byte.
301    fn as_opcode(&self) -> u8 {
302        match self {
303            Self::Absolute => Self::Absolute as u8,
304            Self::IfEqual => Self::IfEqual as u8,
305            Self::IfGreater => Self::IfGreater as u8,
306            Self::IfGreaterOrEqual => Self::IfGreaterOrEqual as u8,
307            Self::IfAnd => Self::IfAnd as u8,
308            Self::IfNotEqual => Self::IfNotEqual as u8,
309            Self::IfSignedGreater => Self::IfSignedGreater as u8,
310            Self::IfSignedGreaterOrEqual => Self::IfSignedGreaterOrEqual as u8,
311            Self::Call => Self::Call as u8,
312            Self::Exit => Self::Exit as u8,
313            Self::IfLessThan => Self::IfLessThan as u8,
314            Self::IfLessThanOrEqual => Self::IfLessThanOrEqual as u8,
315            Self::IfSignedLessThan => Self::IfSignedLessThan as u8,
316            Self::IfSignedLessThanOrEqual => Self::IfSignedLessThanOrEqual as u8,
317        }
318    }
319}
320
321/// Represents a full jump opcode: class, source, operation.
322#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
323pub struct JumpOpcode {
324    class: OpcodeClass,
325    source: SourceOperand,
326    operation: JumpOperation,
327}
328
329impl JumpOpcode {
330    /// Creates an instance of this object from a full, raw instruction.
331    fn from_raw_instruction(instruction: u64) -> Result<Self> {
332        let class = OpcodeClass::from_raw_instruction(instruction);
333        match class {
334            OpcodeClass::Jump | OpcodeClass::Jump32 => (),
335            _ => return Err(Error::InvalidOpcode(instruction as u8)),
336        }
337
338        Ok(Self {
339            class,
340            source: SourceOperand::from_raw_instruction(instruction),
341            operation: JumpOperation::from_raw_instruction(instruction)?,
342        })
343    }
344
345    /// Returns the full opcode (first byte) for this instruction.
346    fn as_opcode(&self) -> u8 {
347        self.class.as_opcode() | self.source.as_opcode() | self.operation.as_opcode()
348    }
349
350    /// Returns the opcode's class.
351    ///
352    /// # Example
353    /// ```
354    /// use bpf_ins::{Instruction, Opcode, OpcodeClass, Register};
355    ///
356    /// let instruction = Instruction::exit();
357    /// let opcode = instruction.get_opcode();
358    /// assert!(matches!(opcode, Opcode::Jump(_)));
359    /// if let Opcode::Jump(jump) = opcode {
360    ///     assert!(matches!(jump.get_class(), OpcodeClass::Jump));
361    /// }
362    /// ```
363    pub fn get_class(&self) -> &OpcodeClass {
364        &self.class
365    }
366
367    /// Returns the opcode's source operand.
368    ///
369    /// # Example
370    /// ```
371    /// use bpf_ins::{Instruction, Opcode, Register, SourceOperand};
372    ///
373    /// let instruction = Instruction::exit();
374    /// let opcode = instruction.get_opcode();
375    /// assert!(matches!(opcode, Opcode::Jump(_)));
376    /// if let Opcode::Jump(jump) = opcode {
377    ///     assert!(matches!(jump.get_source(), SourceOperand::Immediate));
378    /// }
379    /// ```
380    pub fn get_source(&self) -> &SourceOperand {
381        &self.source
382    }
383
384    /// Returns the jump operation.
385    ///
386    /// # Example
387    /// ```
388    /// use bpf_ins::{Instruction, JumpOperation, Opcode, Register};
389    ///
390    /// let instruction = Instruction::exit();
391    /// let opcode = instruction.get_opcode();
392    /// assert!(matches!(opcode, Opcode::Jump(_)));
393    /// if let Opcode::Jump(jump) = opcode {
394    ///     assert!(matches!(jump.get_operation(), JumpOperation::Exit));
395    /// }
396    /// ```
397    pub fn get_operation(&self) -> &JumpOperation {
398        &self.operation
399    }
400}
401
402/// The memory operation size portion of the instruction's opcode.
403#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
404pub enum MemoryOpSize {
405    Word = 0x00,
406    HalfWord = 0x08,
407    Byte = 0x10,
408    DoubleWord = 0x18,
409}
410
411impl MemoryOpSize {
412    const MASK: u64 = 0x18;
413
414    /// Creates an instance of this object from a full, raw instruction.
415    fn from_raw_instruction(instruction: u64) -> Result<Self> {
416        let size = (instruction & Self::MASK) as u8;
417        match size {
418            x if x == Self::Word as u8 => Ok(Self::Word),
419            x if x == Self::HalfWord as u8 => Ok(Self::HalfWord),
420            x if x == Self::Byte as u8 => Ok(Self::Byte),
421            x if x == Self::DoubleWord as u8 => Ok(Self::DoubleWord),
422            x => Err(Error::InvalidMemoryOpSize(x)),
423        }
424    }
425
426    /// Returns the 2 bits that makes up this value in the opcode byte.
427    fn as_opcode(&self) -> u8 {
428        match self {
429            Self::Word => Self::Word as u8,
430            Self::HalfWord => Self::HalfWord as u8,
431            Self::Byte => Self::Byte as u8,
432            Self::DoubleWord => Self::DoubleWord as u8,
433        }
434    }
435}
436
437/// The memory operation mode portion of the instruction's opcode.
438#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
439pub enum MemoryOpMode {
440    Immediate = 0x00,
441    Memory = 0x60,
442    Atomic = 0xc0,
443}
444
445impl MemoryOpMode {
446    const MASK: u64 = 0xe0;
447
448    /// Creates an instance of this object from a full, raw instruction.
449    fn from_raw_instruction(instruction: u64) -> Result<Self> {
450        let mode = (instruction & Self::MASK) as u8;
451        match mode {
452            x if x == Self::Immediate as u8 => Ok(Self::Immediate),
453            x if x == Self::Memory as u8 => Ok(Self::Memory),
454            x if x == Self::Atomic as u8 => Ok(Self::Atomic),
455            x => Err(Error::InvalidMemoryOpMode(x)),
456        }
457    }
458
459    /// Returns the 2 bits that makes up this value in the opcode byte.
460    fn as_opcode(&self) -> u8 {
461        match self {
462            Self::Immediate => Self::Immediate as u8,
463            Self::Memory => Self::Memory as u8,
464            Self::Atomic => Self::Atomic as u8,
465        }
466    }
467}
468
469/// The type of immediate load to perform on a register. Used for adding type information
470/// to BPF function calls.
471#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
472pub enum MemoryOpLoadType {
473    Void,
474    Map,
475    MapValue,
476    BtfId,
477    Function,
478    MapIndex,
479    MapIndexValue,
480}
481
482impl MemoryOpLoadType {
483    const fn register_identifier(&self) -> Register {
484        match self {
485            Self::Void => Register::R0,
486            Self::Map => Register::R1,
487            Self::MapValue => Register::R2,
488            Self::BtfId => Register::R3,
489            Self::Function => Register::R4,
490            Self::MapIndex => Register::R5,
491            Self::MapIndexValue => Register::R6,
492        }
493    }
494}
495
496/// Represents a full memory opcode: class, size, mode.
497#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
498pub struct MemoryOpcode {
499    class: OpcodeClass,
500    size: MemoryOpSize,
501    mode: MemoryOpMode,
502}
503
504impl MemoryOpcode {
505    /// Creates an instance of this object from a full, raw instruction.
506    fn from_raw_instruction(instruction: u64) -> Result<Self> {
507        let class = OpcodeClass::from_raw_instruction(instruction);
508        match class {
509            OpcodeClass::Load
510            | OpcodeClass::LoadReg
511            | OpcodeClass::Store
512            | OpcodeClass::StoreReg => (),
513            _ => return Err(Error::InvalidOpcode(instruction as u8)),
514        }
515
516        Ok(Self {
517            class,
518            size: MemoryOpSize::from_raw_instruction(instruction)?,
519            mode: MemoryOpMode::from_raw_instruction(instruction)?,
520        })
521    }
522
523    /// Returns the full opcode (first byte) for this instruction.
524    fn as_opcode(&self) -> u8 {
525        self.class.as_opcode() | self.size.as_opcode() | self.mode.as_opcode()
526    }
527
528    /// Returns the opcode's class.
529    ///
530    /// # Example
531    /// ```
532    /// use bpf_ins::{Instruction, Opcode, OpcodeClass, Register};
533    ///
534    /// let instruction = Instruction::storex64(Register::R1, 0, Register::R2);
535    /// let opcode = instruction.get_opcode();
536    /// assert!(matches!(opcode, Opcode::Memory(_)));
537    /// if let Opcode::Memory(memory) = opcode {
538    ///     assert!(matches!(memory.get_class(), OpcodeClass::StoreReg));
539    /// }
540    /// ```
541    pub fn get_class(&self) -> &OpcodeClass {
542        &self.class
543    }
544
545    /// Returns the memory operation size.
546    ///
547    /// # Example
548    /// ```
549    /// use bpf_ins::{Instruction, MemoryOpSize, Opcode, Register};
550    ///
551    /// let instruction = Instruction::storex64(Register::R1, 0, Register::R2);
552    /// let opcode = instruction.get_opcode();
553    /// assert!(matches!(opcode, Opcode::Memory(_)));
554    /// if let Opcode::Memory(memory) = opcode {
555    ///     assert!(matches!(memory.get_size(), MemoryOpSize::DoubleWord));
556    /// }
557    /// ```
558    pub fn get_size(&self) -> &MemoryOpSize {
559        &self.size
560    }
561
562    /// Returns the memory operation mode.
563    ///
564    /// # Example
565    /// ```
566    /// use bpf_ins::{Instruction, MemoryOpMode, Opcode, Register};
567    ///
568    /// let instruction = Instruction::storex64(Register::R1, 0, Register::R2);
569    /// let opcode = instruction.get_opcode();
570    /// assert!(matches!(opcode, Opcode::Memory(_)));
571    /// if let Opcode::Memory(memory) = opcode {
572    ///     assert!(matches!(memory.get_mode(), MemoryOpMode::Memory));
573    /// }
574    /// ```
575    pub fn get_mode(&self) -> &MemoryOpMode {
576        &self.mode
577    }
578}
579
580/// Defines all available registers.
581#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
582pub enum Register {
583    #[default]
584    R0,
585    R1,
586    R2,
587    R3,
588    R4,
589    R5,
590    R6,
591    R7,
592    R8,
593    R9,
594    R10,
595}
596
597impl Register {
598    /// Returns a register that corresponds to the given integer.
599    ///
600    /// # Arguments
601    ///
602    /// * `n` - The integer representing the register.
603    ///
604    /// # Example
605    /// ```
606    /// use bpf_ins::{Instruction, Register};
607    ///
608    /// assert_eq!(Register::from_num(5).unwrap(), Register::R5)
609    /// ```
610    pub fn from_num(n: u8) -> Result<Self> {
611        match n {
612            0 => Ok(Self::R0),
613            1 => Ok(Self::R1),
614            2 => Ok(Self::R2),
615            3 => Ok(Self::R3),
616            4 => Ok(Self::R4),
617            5 => Ok(Self::R5),
618            6 => Ok(Self::R6),
619            7 => Ok(Self::R7),
620            8 => Ok(Self::R8),
621            9 => Ok(Self::R9),
622            10 => Ok(Self::R10),
623            n => Err(Error::InvalidRegisterNumber(n)),
624        }
625    }
626
627    /// Returns the integer representation of a register.
628    ///
629    /// # Example
630    /// ```
631    /// use bpf_ins::Register;
632    ///
633    /// let register = Register::R5;
634    /// assert_eq!(register.as_num(), 5)
635    /// ```
636    pub fn as_num(&self) -> u8 {
637        match self {
638            Self::R0 => 0,
639            Self::R1 => 1,
640            Self::R2 => 2,
641            Self::R3 => 3,
642            Self::R4 => 4,
643            Self::R5 => 5,
644            Self::R6 => 6,
645            Self::R7 => 7,
646            Self::R8 => 8,
647            Self::R9 => 9,
648            Self::R10 => 10,
649        }
650    }
651
652    /// Returns the string representation of a register.
653    ///
654    /// # Example
655    /// ```
656    /// use bpf_ins::{MemoryOpSize, Register};
657    ///
658    /// let register = Register::R5;
659    /// assert_eq!(register.as_str(MemoryOpSize::DoubleWord), "r5")
660    /// ```
661    pub fn as_str(&self, size: MemoryOpSize) -> &'static str {
662        match (self, size) {
663            (Self::R0, MemoryOpSize::Byte) => "b0",
664            (Self::R1, MemoryOpSize::Byte) => "b1",
665            (Self::R2, MemoryOpSize::Byte) => "b2",
666            (Self::R3, MemoryOpSize::Byte) => "b3",
667            (Self::R4, MemoryOpSize::Byte) => "b4",
668            (Self::R5, MemoryOpSize::Byte) => "b5",
669            (Self::R6, MemoryOpSize::Byte) => "b6",
670            (Self::R7, MemoryOpSize::Byte) => "b7",
671            (Self::R8, MemoryOpSize::Byte) => "b8",
672            (Self::R9, MemoryOpSize::Byte) => "b9",
673            (Self::R10, MemoryOpSize::Byte) => "b10",
674            (Self::R0, MemoryOpSize::HalfWord) => "h0",
675            (Self::R1, MemoryOpSize::HalfWord) => "h1",
676            (Self::R2, MemoryOpSize::HalfWord) => "h2",
677            (Self::R3, MemoryOpSize::HalfWord) => "h3",
678            (Self::R4, MemoryOpSize::HalfWord) => "h4",
679            (Self::R5, MemoryOpSize::HalfWord) => "h5",
680            (Self::R6, MemoryOpSize::HalfWord) => "h6",
681            (Self::R7, MemoryOpSize::HalfWord) => "h7",
682            (Self::R8, MemoryOpSize::HalfWord) => "h8",
683            (Self::R9, MemoryOpSize::HalfWord) => "h9",
684            (Self::R10, MemoryOpSize::HalfWord) => "h10",
685            (Self::R0, MemoryOpSize::Word) => "w0",
686            (Self::R1, MemoryOpSize::Word) => "w1",
687            (Self::R2, MemoryOpSize::Word) => "w2",
688            (Self::R3, MemoryOpSize::Word) => "w3",
689            (Self::R4, MemoryOpSize::Word) => "w4",
690            (Self::R5, MemoryOpSize::Word) => "w5",
691            (Self::R6, MemoryOpSize::Word) => "w6",
692            (Self::R7, MemoryOpSize::Word) => "w7",
693            (Self::R8, MemoryOpSize::Word) => "w8",
694            (Self::R9, MemoryOpSize::Word) => "w9",
695            (Self::R10, MemoryOpSize::Word) => "w10",
696            (Self::R0, MemoryOpSize::DoubleWord) => "r0",
697            (Self::R1, MemoryOpSize::DoubleWord) => "r1",
698            (Self::R2, MemoryOpSize::DoubleWord) => "r2",
699            (Self::R3, MemoryOpSize::DoubleWord) => "r3",
700            (Self::R4, MemoryOpSize::DoubleWord) => "r4",
701            (Self::R5, MemoryOpSize::DoubleWord) => "r5",
702            (Self::R6, MemoryOpSize::DoubleWord) => "r6",
703            (Self::R7, MemoryOpSize::DoubleWord) => "r7",
704            (Self::R8, MemoryOpSize::DoubleWord) => "r8",
705            (Self::R9, MemoryOpSize::DoubleWord) => "r9",
706            (Self::R10, MemoryOpSize::DoubleWord) => "r10",
707        }
708    }
709
710    fn get_dst(instruction: u64) -> Result<Register> {
711        Self::from_num(((instruction >> 8) & 0xf) as u8)
712    }
713
714    fn get_src(instruction: u64) -> Result<Register> {
715        Self::from_num(((instruction >> 12) & 0xf) as u8)
716    }
717}
718
719/// An enum that holds on of the possible opcodes.
720#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
721pub enum Opcode {
722    Arithmetic(ArithmeticOpcode),
723    Jump(JumpOpcode),
724    Memory(MemoryOpcode),
725}
726
727impl Opcode {
728    /// Creates an instance of this object from a full, raw instruction.
729    fn from_raw_instruction(instruction: u64) -> Result<Self> {
730        let class = OpcodeClass::from_raw_instruction(instruction);
731        match class {
732            OpcodeClass::Arithmetic | OpcodeClass::Arithmetic64 => Ok(Self::Arithmetic(
733                ArithmeticOpcode::from_raw_instruction(instruction)?,
734            )),
735            OpcodeClass::Jump | OpcodeClass::Jump32 => {
736                Ok(Self::Jump(JumpOpcode::from_raw_instruction(instruction)?))
737            }
738            OpcodeClass::Load
739            | OpcodeClass::LoadReg
740            | OpcodeClass::Store
741            | OpcodeClass::StoreReg => Ok(Self::Memory(MemoryOpcode::from_raw_instruction(
742                instruction,
743            )?)),
744        }
745    }
746
747    /// Returns the full opcode (first byte) for this instruction.
748    fn as_opcode(&self) -> u8 {
749        match self {
750            Self::Arithmetic(arithmetic) => arithmetic.as_opcode(),
751            Self::Jump(jump) => jump.as_opcode(),
752            Self::Memory(memory) => memory.as_opcode(),
753        }
754    }
755
756    /// Returns whether the instruction is wide (uses two 64-bit numbers).
757    fn is_wide(&self) -> bool {
758        if let Self::Memory(memory_instruction) = self {
759            matches!(memory_instruction.size, MemoryOpSize::DoubleWord)
760                && matches!(memory_instruction.class, OpcodeClass::Load)
761        } else {
762            false
763        }
764    }
765}
766
767/// Represents a full eBPF instruction: opcode, src register, dst register, offset, immediate.
768#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
769pub struct Instruction {
770    opcode: Opcode,
771    dst_reg: Register,
772    src_reg: Register,
773    offset: i16,
774    imm: i64,
775}
776
777impl Instruction {
778    /// Given a `u64` slice, this decodes a single instruction. Since eBPF instructions
779    /// can be "wide", meaning a single instruction is represented by two 64-bit values,
780    /// a slice is required. The user must check if the instruction was wide by calling
781    /// `is_wide` when deciding how many instructions to advance the slice before the
782    /// next invocation of this function.
783    ///
784    /// # Arguments
785    ///
786    /// * `instructions` - A slice of raw eBPF instructions.
787    ///
788    /// # Example
789    /// ```
790    /// use bpf_ins::{Instruction, Opcode, Register};
791    ///
792    /// let instructions = [ 0x000000fff81a7b ];
793    /// let instruction = Instruction::decode(&instructions).unwrap();
794    /// assert!(matches!(instruction.get_opcode(), Opcode::Memory(_)));
795    /// assert!(matches!(instruction.get_dst_reg(), Register::R10));
796    /// assert!(matches!(instruction.get_src_reg(), Register::R1));
797    /// assert!(matches!(instruction.get_offset(), -8));
798    /// assert!(matches!(instruction.get_imm(), 0));
799    /// ```
800    pub fn decode(instructions: &[u64]) -> Result<Self> {
801        if instructions.is_empty() {
802            return Err(Error::NotEnoughInstructions);
803        }
804
805        let opcode = Opcode::from_raw_instruction(instructions[0])?;
806        let dst_reg = Register::get_dst(instructions[0])?;
807        let src_reg = Register::get_src(instructions[0])?;
808        let offset = ((instructions[0] >> 16) & 0xffff) as i16;
809        let mut imm = ((instructions[0] >> 32) & 0xffffffff) as i64;
810        if opcode.is_wide() {
811            if instructions.len() < 2 {
812                return Err(Error::NotEnoughInstructions);
813            } else {
814                imm |= (instructions[1] & 0xffffffff00000000) as i64;
815            }
816        }
817
818        Ok(Self {
819            opcode,
820            dst_reg,
821            src_reg,
822            offset,
823            imm,
824        })
825    }
826
827    /// Encodes this instruction object into raw 64-bit eBPF instructions. If the
828    /// instruction was wide, the second entry of the tuple is populated with the
829    /// extended part of the instruction.
830    ///
831    /// # Example
832    /// ```
833    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
834    ///
835    /// let instruction = Instruction::load(Register::R10, 0xdeadbeef, MemoryOpSize::DoubleWord);
836    /// assert!(instruction.is_wide());
837    /// assert_eq!(instruction.encode(), (0xdeadbeef00000a18, Some(0)));
838    /// ```
839    pub fn encode(&self) -> (u64, Option<u64>) {
840        let opcode = self.opcode.as_opcode() as u64;
841        let dst_reg = self.dst_reg.as_num() as u64;
842        let src_reg = self.src_reg.as_num() as u64;
843        let offset = (self.offset as u64) & 0xffff;
844        let imm = self.imm as u64;
845        let n = opcode | (dst_reg << 8) | (src_reg << 12) | (offset << 16) | (imm << 32);
846        if self.opcode.is_wide() {
847            let x = imm & 0xffffffff00000000;
848            (n, Some(x))
849        } else {
850            (n, None)
851        }
852    }
853
854    /// Returns the "opcode" portion of this instruction.
855    ///
856    /// # Example
857    /// ```
858    /// use bpf_ins::{Instruction, MemoryOpSize, Opcode, Register};
859    ///
860    /// let instruction = Instruction::addx64(Register::R5, Register::R6);
861    /// assert!(matches!(instruction.get_opcode(), Opcode::Arithmetic(_)));
862    ///
863    /// let instruction = Instruction::exit();
864    /// assert!(matches!(instruction.get_opcode(), Opcode::Jump(_)));
865    ///
866    /// let instruction = Instruction::load(Register::R10, 0xdeadbeef, MemoryOpSize::Byte);
867    /// assert!(matches!(instruction.get_opcode(), Opcode::Memory(_)));
868    ///
869    /// let instruction = Instruction::store64(Register::R10, 0, 0xdeadbeef);
870    /// assert!(matches!(instruction.get_opcode(), Opcode::Memory(_)));
871    /// ```
872    pub fn get_opcode(&self) -> Opcode {
873        self.opcode
874    }
875
876    /// Returns "source register" portion of this instruction.
877    ///
878    /// # Example
879    /// ```
880    /// use bpf_ins::{Instruction, Register};
881    ///
882    /// let instruction = Instruction::addx64(Register::R2, Register::R3);
883    /// assert_eq!(instruction.get_src_reg(), Register::R3);
884    /// ```
885    pub fn get_src_reg(&self) -> Register {
886        self.src_reg
887    }
888
889    /// Returns "destination register" portion of this instruction.
890    ///
891    /// # Example
892    /// ```
893    /// use bpf_ins::{Instruction, Register};
894    ///
895    /// let instruction = Instruction::addx64(Register::R2, Register::R3);
896    /// assert_eq!(instruction.get_dst_reg(), Register::R2);
897    /// ```
898    pub fn get_dst_reg(&self) -> Register {
899        self.dst_reg
900    }
901
902    /// Returns the "offset" portion of this instruction.
903    ///
904    /// # Example
905    /// ```
906    /// use bpf_ins::{Instruction, Register};
907    ///
908    /// let instruction = Instruction::store64(Register::R10, -300, 0);
909    /// assert_eq!(instruction.get_offset(), -300);
910    /// ```
911    pub fn get_offset(&self) -> i16 {
912        self.offset
913    }
914
915    /// Returns the "immediate" portion of this instruction.
916    ///
917    /// # Example
918    /// ```
919    /// use bpf_ins::{Instruction, Register};
920    ///
921    /// let instruction = Instruction::store64(Register::R10, 0, 0xffbbccdd);
922    /// assert_eq!(instruction.get_imm(), 0xffbbccdd);
923    /// ```
924    pub fn get_imm(&self) -> i64 {
925        self.imm
926    }
927
928    /// Returns whether this instruction is wide or not. That is, if it's
929    /// represented by two 64-bit values when encoded.
930    ///
931    /// # Example
932    /// ```
933    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
934    ///
935    /// let instruction = Instruction::load(Register::R9, 0xdeadbeef, MemoryOpSize::DoubleWord);
936    /// assert!(instruction.is_wide());
937    /// ```
938    pub fn is_wide(&self) -> bool {
939        self.opcode.is_wide()
940    }
941
942    /// Helper function for encoding immediate ALU instructions.
943    ///
944    /// # Arguments
945    ///
946    /// * `reg` - The register on which the operation is performed.
947    /// * `imm` - The immediate value of the operation.
948    /// * `op` - The type of arithmetic operation.
949    ///
950    /// # Example
951    /// ```
952    /// use bpf_ins::{ArithmeticOperation, Instruction, Register};
953    ///
954    /// let instruction = Instruction::alu32(Register::R1, -10000, ArithmeticOperation::Add);
955    /// assert_eq!(instruction.encode(), (0xffffd8f000000104, None))
956    /// ```
957    pub const fn alu32(reg: Register, imm: i32, op: ArithmeticOperation) -> Self {
958        let opcode = Opcode::Arithmetic(ArithmeticOpcode {
959            class: OpcodeClass::Arithmetic,
960            source: SourceOperand::Immediate,
961            operation: op,
962            order: SwapOrder::Little,
963        });
964
965        Self {
966            opcode,
967            dst_reg: reg,
968            src_reg: Register::R0,
969            offset: 0,
970            imm: imm as i64,
971        }
972    }
973
974    /// Helper function for encoding 64-bit immediate ALU instructions.
975    ///
976    /// # Arguments
977    ///
978    /// * `reg` - The register on which the operation is performed.
979    /// * `imm` - The immediate value of the operation.
980    /// * `op` - The type of arithmetic operation.
981    ///
982    /// # Example
983    /// ```
984    /// use bpf_ins::{ArithmeticOperation, Instruction, Register};
985    ///
986    /// let instruction = Instruction::alu64(Register::R1, -10000, ArithmeticOperation::Add);
987    /// assert_eq!(instruction.encode(), (0xffffd8f000000107, None))
988    /// ```
989    pub const fn alu64(reg: Register, imm: i32, op: ArithmeticOperation) -> Self {
990        let opcode = Opcode::Arithmetic(ArithmeticOpcode {
991            class: OpcodeClass::Arithmetic64,
992            source: SourceOperand::Immediate,
993            operation: op,
994            order: SwapOrder::Little,
995        });
996
997        Self {
998            opcode,
999            dst_reg: reg,
1000            src_reg: Register::R0,
1001            offset: 0,
1002            imm: imm as i64,
1003        }
1004    }
1005
1006    /// Helper function for encoding register ALU instructions.
1007    ///
1008    /// # Arguments
1009    ///
1010    /// * `dst_reg` - The destination register involved in the operation.
1011    /// * `src_reg` - The source register involved in the operation.
1012    /// * `op` - The type of arithmetic operation.
1013    ///
1014    /// # Example
1015    /// ```
1016    /// use bpf_ins::{ArithmeticOperation, Instruction, Register};
1017    ///
1018    /// let instruction = Instruction::alux32(Register::R1, Register::R2, ArithmeticOperation::Mul);
1019    /// assert_eq!(instruction.encode(), (0x212c, None))
1020    /// ```
1021    pub const fn alux32(dst_reg: Register, src_reg: Register, op: ArithmeticOperation) -> Self {
1022        let opcode = Opcode::Arithmetic(ArithmeticOpcode {
1023            class: OpcodeClass::Arithmetic,
1024            source: SourceOperand::Register,
1025            operation: op,
1026            order: SwapOrder::Little,
1027        });
1028
1029        Self {
1030            opcode,
1031            dst_reg,
1032            src_reg,
1033            offset: 0,
1034            imm: 0,
1035        }
1036    }
1037
1038    /// Helper function for encoding 64-bit register ALU instructions.
1039    ///
1040    /// # Arguments
1041    ///
1042    /// * `dst_reg` - The destination register involved in the operation.
1043    /// * `src_reg` - The source register involved in the operation.
1044    /// * `op` - The type of arithmetic operation.
1045    ///
1046    /// # Example
1047    /// ```
1048    /// use bpf_ins::{ArithmeticOperation, Instruction, Register};
1049    ///
1050    /// let instruction = Instruction::alux64(Register::R1, Register::R2, ArithmeticOperation::Mul);
1051    /// assert_eq!(instruction.encode(), (0x212f, None))
1052    /// ```
1053    pub const fn alux64(dst_reg: Register, src_reg: Register, op: ArithmeticOperation) -> Self {
1054        let opcode = Opcode::Arithmetic(ArithmeticOpcode {
1055            class: OpcodeClass::Arithmetic64,
1056            source: SourceOperand::Register,
1057            operation: op,
1058            order: SwapOrder::Little,
1059        });
1060
1061        Self {
1062            opcode,
1063            dst_reg,
1064            src_reg,
1065            offset: 0,
1066            imm: 0,
1067        }
1068    }
1069
1070    /// Helper function for encoding 32-bit immediate add instructions. Equivalent to calling
1071    /// `Instruction::alu32(reg, imm, ArithmeticOperation::Add)`.
1072    ///
1073    /// # Arguments
1074    ///
1075    /// * `reg` - The register on which the operation is performed.
1076    /// * `imm` - The immediate value of the operation.
1077    ///
1078    /// # Example
1079    /// ```
1080    /// use bpf_ins::{Instruction, Register};
1081    ///
1082    /// let instruction = Instruction::add32(Register::R1, -10000);
1083    /// assert_eq!(instruction.encode(), (0xffffd8f000000104, None))
1084    /// ```
1085    pub const fn add32(reg: Register, imm: i32) -> Self {
1086        Self::alu32(reg, imm, ArithmeticOperation::Add)
1087    }
1088
1089    /// Helper function for encoding 64-bit immediate add instructions. Equivalent to calling
1090    /// `Instruction::alu64(reg, imm, ArithmeticOperation::Add)`.
1091    ///
1092    /// # Arguments
1093    ///
1094    /// * `reg` - The register on which the operation is performed.
1095    /// * `imm` - The immediate value of the operation.
1096    ///
1097    /// # Example
1098    /// ```
1099    /// use bpf_ins::{Instruction, Register};
1100    ///
1101    /// let instruction = Instruction::add64(Register::R1, -10000);
1102    /// assert_eq!(instruction.encode(), (0xffffd8f000000107, None))
1103    /// ```
1104    pub const fn add64(reg: Register, imm: i32) -> Self {
1105        Self::alu64(reg, imm, ArithmeticOperation::Add)
1106    }
1107
1108    /// Helper function for encoding 32-bit register add instructions. Equivalent to calling
1109    /// `Instruction::alux32(dst_reg, src_reg, ArithmeticOperation::Add)`.
1110    ///
1111    /// # Arguments
1112    ///
1113    /// * `dst_reg` - The destination register involved in the operation.
1114    /// * `src_reg` - The source register involved in the operation.
1115    ///
1116    /// # Example
1117    /// ```
1118    /// use bpf_ins::{ArithmeticOperation, Instruction, Register};
1119    ///
1120    /// let instruction = Instruction::addx32(Register::R1, Register::R2);
1121    /// assert_eq!(instruction.encode(), (0x210c, None))
1122    /// ```
1123    pub const fn addx32(dst_reg: Register, src_reg: Register) -> Self {
1124        Self::alux32(dst_reg, src_reg, ArithmeticOperation::Add)
1125    }
1126
1127    /// Helper function for encoding 64-bit register add instructions. Equivalent to calling
1128    /// `Instruction::alux64(dst_reg, src_reg, ArithmeticOperation::Add)`.
1129    ///
1130    /// # Arguments
1131    ///
1132    /// * `dst_reg` - The destination register involved in the operation.
1133    /// * `src_reg` - The source register involved in the operation.
1134    ///
1135    /// # Example
1136    /// ```
1137    /// use bpf_ins::{Instruction, Register};
1138    ///
1139    /// let instruction = Instruction::addx64(Register::R1, Register::R2);
1140    /// assert_eq!(instruction.encode(), (0x210f, None))
1141    /// ```
1142    pub const fn addx64(dst_reg: Register, src_reg: Register) -> Self {
1143        Self::alux64(dst_reg, src_reg, ArithmeticOperation::Add)
1144    }
1145
1146    /// Helper function for encoding immediate 32-bit ALU move instructions. Equivalent to
1147    /// calling `Instruction::alu32(reg, imm, ArithmeticOperation::Mov)`.
1148    ///
1149    /// # Arguments
1150    ///
1151    /// * `reg` - The register involved in the operation.
1152    /// * `imm` - The immediate value to move into the register.
1153    ///
1154    /// # Example
1155    /// ```
1156    /// use bpf_ins::{Instruction, Register};
1157    ///
1158    /// let instruction = Instruction::mov32(Register::R7, 0xfffffff);
1159    /// assert_eq!(instruction.encode(), (0xfffffff000007b4, None))
1160    /// ```
1161    pub const fn mov32(reg: Register, imm: i32) -> Self {
1162        Self::alu32(reg, imm, ArithmeticOperation::Mov)
1163    }
1164
1165    /// Helper function for encoding immediate 64-bit ALU move instructions. Equivalent to
1166    /// calling `Instruction::alu64(reg, imm, ArithmeticOperation::Mov)`.
1167    ///
1168    /// # Arguments
1169    ///
1170    /// * `reg` - The register involved in the operation.
1171    /// * `imm` - The immediate value to move into the register.
1172    ///
1173    /// # Example
1174    /// ```
1175    /// use bpf_ins::{Instruction, Register};
1176    ///
1177    /// let instruction = Instruction::mov64(Register::R7, 0xfffffff);
1178    /// assert_eq!(instruction.encode(), (0xfffffff000007b7, None))
1179    /// ```
1180    pub const fn mov64(reg: Register, imm: i32) -> Self {
1181        Self::alu64(reg, imm, ArithmeticOperation::Mov)
1182    }
1183
1184    /// Helper function for encoding register 32-bit ALU move instructions. Equivalent to
1185    /// calling `Instruction::alux32(dst_reg, src_reg, ArithmeticOperation::Mov)`.
1186    ///
1187    /// # Arguments
1188    ///
1189    /// * `dst_reg` - The destination register involved in the operation.
1190    /// * `src_reg` - The source register involved in the operation.
1191    ///
1192    /// # Example
1193    /// ```
1194    /// use bpf_ins::{Instruction, Register};
1195    ///
1196    /// let instruction = Instruction::movx32(Register::R7, Register::R8);
1197    /// assert_eq!(instruction.encode(), (0x87bc, None))
1198    /// ```
1199    pub const fn movx32(dst_reg: Register, src_reg: Register) -> Self {
1200        Self::alux32(dst_reg, src_reg, ArithmeticOperation::Mov)
1201    }
1202
1203    /// Helper function for encoding register 64-bit ALU move instructions. Equivalent to
1204    /// calling `Instruction::alux64(dst_reg, src_reg, ArithmeticOperation::Mov)`.
1205    ///
1206    /// # Arguments
1207    ///
1208    /// * `dst_reg` - The destination register involved in the operation.
1209    /// * `src_reg` - The source register involved in the operation.
1210    ///
1211    /// # Example
1212    /// ```
1213    /// use bpf_ins::{Instruction, Register};
1214    ///
1215    /// let instruction = Instruction::movx64(Register::R7, Register::R8);
1216    /// assert_eq!(instruction.encode(), (0x87bf, None))
1217    /// ```
1218    pub const fn movx64(dst_reg: Register, src_reg: Register) -> Self {
1219        Self::alux64(dst_reg, src_reg, ArithmeticOperation::Mov)
1220    }
1221
1222    /// Helper function for creating instructions that load values from memory.
1223    ///
1224    /// # Arguments
1225    ///
1226    /// * `reg` - The register to load the value into.
1227    /// * `imm` - The memory address.
1228    /// * `size` - The size of the load.
1229    ///
1230    /// # Example
1231    /// ```
1232    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
1233    ///
1234    /// let instruction = Instruction::load(Register::R9, 0x7fff880000000000, MemoryOpSize::Byte);
1235    /// assert_eq!(instruction.encode(), (0x910, None))
1236    /// ```
1237    pub const fn load(reg: Register, imm: i64, size: MemoryOpSize) -> Self {
1238        let opcode = Opcode::Memory(MemoryOpcode {
1239            class: OpcodeClass::Load,
1240            size,
1241            mode: MemoryOpMode::Immediate,
1242        });
1243
1244        Self {
1245            opcode,
1246            dst_reg: reg,
1247            src_reg: Register::R0,
1248            offset: 0,
1249            imm,
1250        }
1251    }
1252
1253    /// Helper function for creating instructions that load values from memory. This is
1254    /// currently only used for "special" loads, ie: when loading a map fd into a register,
1255    /// the eBPF verifier will replace the fd number with the map's virtual address.
1256    ///
1257    /// # Arguments
1258    ///
1259    /// * `reg` - The register to load the value into.
1260    /// * `imm` - The memory address.
1261    /// * `load_type` - The type to assign to the load.
1262    ///
1263    /// # Example
1264    /// ```
1265    /// use bpf_ins::{Instruction, MemoryOpLoadType, Register};
1266    ///
1267    /// let instruction = Instruction::loadtype(Register::R4, 3, MemoryOpLoadType::Map);
1268    /// assert_eq!(instruction.encode(), (0x300001418, Some(0)));
1269    /// assert_eq!(instruction.get_src_reg(), Register::R1);
1270    /// ```
1271    pub const fn loadtype(reg: Register, imm: i64, load_type: MemoryOpLoadType) -> Self {
1272        let opcode = Opcode::Memory(MemoryOpcode {
1273            class: OpcodeClass::Load,
1274            size: MemoryOpSize::DoubleWord,
1275            mode: MemoryOpMode::Immediate,
1276        });
1277
1278        Self {
1279            opcode,
1280            dst_reg: reg,
1281            src_reg: load_type.register_identifier(),
1282            offset: 0,
1283            imm,
1284        }
1285    }
1286
1287    /// Helper function for creating instructions that load values from memory into a register
1288    /// using one register as the address value.
1289    ///
1290    /// # Arguments
1291    ///
1292    /// * `dst_reg` - The register to load the value into.
1293    /// * `src_reg` - The register holding the memory address.
1294    /// * `offset` - The offset from the address in `src_reg` to load.
1295    /// * `size` - The size of the value to load from the memory location.
1296    ///
1297    /// # Example
1298    /// ```
1299    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
1300    ///
1301    /// let instruction = Instruction::loadx(Register::R4, Register::R5, -16, MemoryOpSize::Byte);
1302    /// assert_eq!(instruction.encode(), (0xfff05471, None));
1303    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1304    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1305    /// ```
1306    pub const fn loadx(
1307        dst_reg: Register,
1308        src_reg: Register,
1309        offset: i16,
1310        size: MemoryOpSize,
1311    ) -> Self {
1312        let opcode = Opcode::Memory(MemoryOpcode {
1313            class: OpcodeClass::LoadReg,
1314            size,
1315            mode: MemoryOpMode::Memory,
1316        });
1317
1318        Self {
1319            opcode,
1320            dst_reg,
1321            src_reg,
1322            offset,
1323            imm: 0,
1324        }
1325    }
1326
1327    /// Helper function for creating instructions that load a byte from memory. Equivalent
1328    /// to calling `Instruction::loadx(dst_reg, src_reg, offset, MemoryOpSize::Byte)`.
1329    ///
1330    /// # Arguments
1331    ///
1332    /// * `dst_reg` - The register to load the value into.
1333    /// * `src_reg` - The register holding the memory address.
1334    /// * `offset` - The offset from the address in `src_reg` to load.
1335    ///
1336    /// # Example
1337    /// ```
1338    /// use bpf_ins::{Instruction, Register};
1339    ///
1340    /// let instruction = Instruction::loadx8(Register::R2, Register::R3, -16);
1341    /// assert_eq!(instruction.encode(), (0xfff03271, None));
1342    /// assert_eq!(instruction.get_dst_reg(), Register::R2);
1343    /// assert_eq!(instruction.get_src_reg(), Register::R3);
1344    /// ```
1345    pub const fn loadx8(dst_reg: Register, src_reg: Register, offset: i16) -> Self {
1346        Self::loadx(dst_reg, src_reg, offset, MemoryOpSize::Byte)
1347    }
1348
1349    /// Helper function for creating instructions that load a half word from memory. Equivalent
1350    /// to calling `Instruction::loadx(dst_reg, src_reg, offset, MemoryOpSize::HalfWord)`.
1351    ///
1352    /// # Arguments
1353    ///
1354    /// * `dst_reg` - The register to load the value into.
1355    /// * `src_reg` - The register holding the memory address.
1356    /// * `offset` - The offset from the address in `src_reg` to load.
1357    ///
1358    /// # Example
1359    /// ```
1360    /// use bpf_ins::{Instruction, Register};
1361    ///
1362    /// let instruction = Instruction::loadx16(Register::R1, Register::R2, -16);
1363    /// assert_eq!(instruction.encode(), (0xfff02169, None));
1364    /// assert_eq!(instruction.get_dst_reg(), Register::R1);
1365    /// assert_eq!(instruction.get_src_reg(), Register::R2);
1366    /// ```
1367    pub const fn loadx16(dst_reg: Register, src_reg: Register, offset: i16) -> Self {
1368        Self::loadx(dst_reg, src_reg, offset, MemoryOpSize::HalfWord)
1369    }
1370
1371    /// Helper function for creating instructions that load a word from memory. Equivalent
1372    /// to calling `Instruction::loadx(dst_reg, src_reg, offset, MemoryOpSize::Word)`.
1373    ///
1374    /// # Arguments
1375    ///
1376    /// * `dst_reg` - The register to load the value into.
1377    /// * `src_reg` - The register holding the memory address.
1378    /// * `offset` - The offset from the address in `src_reg` to load.
1379    ///
1380    /// # Example
1381    /// ```
1382    /// use bpf_ins::{Instruction, Register};
1383    ///
1384    /// let instruction = Instruction::loadx32(Register::R8, Register::R9, -16);
1385    /// assert_eq!(instruction.encode(), (0xfff09861, None));
1386    /// assert_eq!(instruction.get_dst_reg(), Register::R8);
1387    /// assert_eq!(instruction.get_src_reg(), Register::R9);
1388    /// ```
1389    pub const fn loadx32(dst_reg: Register, src_reg: Register, offset: i16) -> Self {
1390        Self::loadx(dst_reg, src_reg, offset, MemoryOpSize::Word)
1391    }
1392
1393    /// Helper function for creating instructions that load a double word from memory. Equivalent
1394    /// to calling `Instruction::loadx(dst_reg, src_reg, offset, MemoryOpSize::DoubleWord)`.
1395    ///
1396    /// # Arguments
1397    ///
1398    /// * `dst_reg` - The register to load the value into.
1399    /// * `src_reg` - The register holding the memory address.
1400    /// * `offset` - The offset from the address in `src_reg` to load.
1401    ///
1402    /// # Example
1403    /// ```
1404    /// use bpf_ins::{Instruction, Register};
1405    ///
1406    /// let instruction = Instruction::loadx64(Register::R7, Register::R10, -16);
1407    /// assert_eq!(instruction.encode(), (0xfff0a779, None));
1408    /// assert_eq!(instruction.get_dst_reg(), Register::R7);
1409    /// assert_eq!(instruction.get_src_reg(), Register::R10);
1410    /// ```
1411    pub const fn loadx64(dst_reg: Register, src_reg: Register, offset: i16) -> Self {
1412        Self::loadx(dst_reg, src_reg, offset, MemoryOpSize::DoubleWord)
1413    }
1414
1415    /// Helper function for creating instructions that store immediate values to memory.
1416    ///
1417    /// # Arguments
1418    ///
1419    /// * `reg` - The register containing the memory address.
1420    /// * `offset` - The offset from the address held in `reg` to store the value.
1421    /// * `imm` - The immediate value to store.
1422    /// * `size` - The size of the store operation.
1423    ///
1424    /// # Example
1425    /// ```
1426    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
1427    ///
1428    /// let instruction = Instruction::store(Register::R1, 2808, i64::max_value(),
1429    /// MemoryOpSize::DoubleWord);
1430    /// assert_eq!(instruction.encode(), (0xffffffff0af8017a, None));
1431    /// assert_eq!(instruction.get_dst_reg(), Register::R1);
1432    /// ```
1433    pub const fn store(reg: Register, offset: i16, imm: i64, size: MemoryOpSize) -> Self {
1434        let opcode = Opcode::Memory(MemoryOpcode {
1435            class: OpcodeClass::Store,
1436            size,
1437            mode: MemoryOpMode::Memory,
1438        });
1439
1440        Self {
1441            opcode,
1442            dst_reg: reg,
1443            src_reg: Register::R0,
1444            offset,
1445            imm,
1446        }
1447    }
1448
1449    /// Helper function for creating instructions that store a byte to a memory address.
1450    /// Equivalent to calling `Instruction::store(reg, offset, imm, MemoryOpSize::Byte)`.
1451    ///
1452    /// # Arguments
1453    ///
1454    /// * `reg` - The register containing the memory address.
1455    /// * `offset` - The offset from the address held in `reg` to store the value.
1456    /// * `imm` - The immediate value to store.
1457    ///
1458    /// # Example
1459    /// ```
1460    /// use bpf_ins::{Instruction, Register};
1461    ///
1462    /// let instruction = Instruction::store8(Register::R2, i16::min_value(), i8::max_value());
1463    /// assert_eq!(instruction.get_dst_reg(), Register::R2);
1464    /// assert_eq!(instruction.get_offset(), i16::min_value());
1465    /// assert_eq!(instruction.get_imm(), i8::max_value() as i64);
1466    /// ```
1467    pub const fn store8(reg: Register, offset: i16, imm: i8) -> Self {
1468        Self::store(reg, offset, imm as i64, MemoryOpSize::Byte)
1469    }
1470
1471    /// Helper function for creating instructions that store a half word to a memory address.
1472    /// Equivalent to calling `Instruction::store(reg, offset, imm, MemoryOpSize::HalfWord)`.
1473    ///
1474    /// # Arguments
1475    ///
1476    /// * `reg` - The register containing the memory address.
1477    /// * `offset` - The offset from the address held in `reg` to store the value.
1478    /// * `imm` - The immediate value to store.
1479    ///
1480    /// # Example
1481    /// ```
1482    /// use bpf_ins::{Instruction, Register};
1483    ///
1484    /// let instruction = Instruction::store16(Register::R3, i16::max_value(), i16::min_value());
1485    /// assert_eq!(instruction.get_dst_reg(), Register::R3);
1486    /// assert_eq!(instruction.get_offset(), i16::max_value());
1487    /// assert_eq!(instruction.get_imm(), i16::min_value() as i64);
1488    /// ```
1489    pub const fn store16(reg: Register, offset: i16, imm: i16) -> Self {
1490        Self::store(reg, offset, imm as i64, MemoryOpSize::HalfWord)
1491    }
1492
1493    /// Helper function for creating instructions that store a word to a memory address.
1494    /// Equivalent to calling `Instruction::store(reg, offset, imm, MemoryOpSize::Word)`.
1495    ///
1496    /// # Arguments
1497    ///
1498    /// * `reg` - The register containing the memory address.
1499    /// * `offset` - The offset from the address held in `reg` to store the value.
1500    /// * `imm` - The immediate value to store.
1501    ///
1502    /// # Example
1503    /// ```
1504    /// use bpf_ins::{Instruction, Register};
1505    ///
1506    /// let instruction = Instruction::store32(Register::R4, i16::max_value(), i32::min_value());
1507    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1508    /// assert_eq!(instruction.get_offset(), i16::max_value());
1509    /// assert_eq!(instruction.get_imm(), i32::min_value() as i64);
1510    /// ```
1511    pub const fn store32(reg: Register, offset: i16, imm: i32) -> Self {
1512        Self::store(reg, offset, imm as i64, MemoryOpSize::Word)
1513    }
1514
1515    /// Helper function for creating instructions that store a double word to a memory address.
1516    /// Equivalent to calling `Instruction::store(reg, offset, imm, MemoryOpSize::DoubleWord)`.
1517    ///
1518    /// # Arguments
1519    ///
1520    /// * `reg` - The register containing the memory address.
1521    /// * `offset` - The offset from the address held in `reg` to store the value.
1522    /// * `imm` - The immediate value to store.
1523    ///
1524    /// # Example
1525    /// ```
1526    /// use bpf_ins::{Instruction, Register};
1527    ///
1528    /// let instruction = Instruction::store64(Register::R4, i16::max_value(), i64::min_value());
1529    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1530    /// assert_eq!(instruction.get_offset(), i16::max_value());
1531    /// assert_eq!(instruction.get_imm(), i64::min_value() as i64);
1532    /// ```
1533    pub const fn store64(reg: Register, offset: i16, imm: i64) -> Self {
1534        Self::store(reg, offset, imm, MemoryOpSize::DoubleWord)
1535    }
1536
1537    /// Helper function or creating instructions that store register values to memory.
1538    ///
1539    /// # Arguments
1540    ///
1541    /// * `dst_reg` - The register holding the address of the store operation.
1542    /// * `offset` - The offset, from `dst_reg`, to store the value.
1543    /// * `src_reg` - The register holding the value to be stored.
1544    /// * `size` - The size of the store operation.
1545    ///
1546    /// # Example
1547    /// ```
1548    /// use bpf_ins::{Instruction, MemoryOpSize, Register};
1549    ///
1550    /// let instruction = Instruction::storex(Register::R4, -128, Register::R5, MemoryOpSize::Word);
1551    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1552    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1553    /// assert_eq!(instruction.get_offset(),-128);
1554    /// assert_eq!(instruction.encode(), (0xff805463, None));
1555    /// ```
1556    pub const fn storex(
1557        dst_reg: Register,
1558        offset: i16,
1559        src_reg: Register,
1560        size: MemoryOpSize,
1561    ) -> Self {
1562        let opcode = Opcode::Memory(MemoryOpcode {
1563            class: OpcodeClass::StoreReg,
1564            size,
1565            mode: MemoryOpMode::Memory,
1566        });
1567
1568        Self {
1569            opcode,
1570            dst_reg,
1571            src_reg,
1572            offset,
1573            imm: 0,
1574        }
1575    }
1576
1577    /// Helper function or creating instructions that store a byte from a register into memory.
1578    /// Equivalent to `Instruction::storex(dst_reg, offset, src_reg, MemoryOpSize::Byte)`.
1579    ///
1580    /// # Arguments
1581    ///
1582    /// * `dst_reg` - The register holding the address of the store operation.
1583    /// * `offset` - The offset, from `dst_reg`, to store the value.
1584    /// * `src_reg` - The register holding the value to be stored.
1585    ///
1586    /// # Example
1587    /// ```
1588    /// use bpf_ins::{Instruction, Register};
1589    ///
1590    /// let instruction = Instruction::storex8(Register::R4, -128, Register::R5);
1591    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1592    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1593    /// assert_eq!(instruction.get_offset(),-128);
1594    /// assert_eq!(instruction.encode(), (0xff805473, None));
1595    /// ```
1596    pub const fn storex8(dst_reg: Register, offset: i16, src_reg: Register) -> Self {
1597        Self::storex(dst_reg, offset, src_reg, MemoryOpSize::Byte)
1598    }
1599
1600    /// Helper function or creating instructions that store a half word from a register into memory.
1601    /// Equivalent to `Instruction::storex(dst_reg, offset, src_reg, MemoryOpSize::HalfWord)`.
1602    ///
1603    /// # Arguments
1604    ///
1605    /// * `dst_reg` - The register holding the address of the store operation.
1606    /// * `offset` - The offset, from `dst_reg`, to store the value.
1607    /// * `src_reg` - The register holding the value to be stored.
1608    ///
1609    /// # Example
1610    /// ```
1611    /// use bpf_ins::{Instruction, Register};
1612    ///
1613    /// let instruction = Instruction::storex16(Register::R4, -128, Register::R5);
1614    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1615    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1616    /// assert_eq!(instruction.get_offset(),-128);
1617    /// assert_eq!(instruction.encode(), (0xff80546b, None));
1618    /// ```
1619    pub const fn storex16(dst_reg: Register, offset: i16, src_reg: Register) -> Self {
1620        Self::storex(dst_reg, offset, src_reg, MemoryOpSize::HalfWord)
1621    }
1622
1623    /// Helper function or creating instructions that store a word from a register into memory.
1624    /// Equivalent to `Instruction::storex(dst_reg, offset, src_reg, MemoryOpSize::Word)`.
1625    ///
1626    /// # Arguments
1627    ///
1628    /// * `dst_reg` - The register holding the address of the store operation.
1629    /// * `offset` - The offset, from `dst_reg`, to store the value.
1630    /// * `src_reg` - The register holding the value to be stored.
1631    ///
1632    /// # Example
1633    /// ```
1634    /// use bpf_ins::{Instruction, Register};
1635    ///
1636    /// let instruction = Instruction::storex32(Register::R4, -128, Register::R5);
1637    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1638    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1639    /// assert_eq!(instruction.get_offset(),-128);
1640    /// assert_eq!(instruction.encode(), (0xff805463, None));
1641    /// ```
1642    pub const fn storex32(dst_reg: Register, offset: i16, src_reg: Register) -> Self {
1643        Self::storex(dst_reg, offset, src_reg, MemoryOpSize::Word)
1644    }
1645
1646    /// Helper function or creating instructions that store a double word from a register into memory.
1647    /// Equivalent to `Instruction::storex(dst_reg, offset, src_reg, MemoryOpSize::DoubleWord)`.
1648    ///
1649    /// # Arguments
1650    ///
1651    /// * `dst_reg` - The register holding the address of the store operation.
1652    /// * `offset` - The offset, from `dst_reg`, to store the value.
1653    /// * `src_reg` - The register holding the value to be stored.
1654    ///
1655    /// # Example
1656    /// ```
1657    /// use bpf_ins::{Instruction, Register};
1658    ///
1659    /// let instruction = Instruction::storex64(Register::R4, -128, Register::R5);
1660    /// assert_eq!(instruction.get_dst_reg(), Register::R4);
1661    /// assert_eq!(instruction.get_src_reg(), Register::R5);
1662    /// assert_eq!(instruction.get_offset(),-128);
1663    /// assert_eq!(instruction.encode(), (0xff80547b, None));
1664    /// ```
1665    pub const fn storex64(dst_reg: Register, offset: i16, src_reg: Register) -> Self {
1666        Self::storex(dst_reg, offset, src_reg, MemoryOpSize::DoubleWord)
1667    }
1668
1669    /// Helper function for creating control-flow instructions.
1670    ///
1671    /// # Arguments
1672    ///
1673    /// * `left_reg` - The register on the left side of the operation.
1674    /// * `operation` - The operation.
1675    /// * `right_reg` - The register on the right side of the operation.
1676    /// * `offset` - The offset to jump to, if true.
1677    ///
1678    /// # Example
1679    /// ```
1680    /// use bpf_ins::{Instruction, JumpOperation, Register};
1681    ///
1682    /// let instruction = Instruction::jmp_ifx(Register::R1, JumpOperation::IfGreater,
1683    /// Register::R2, 5);
1684    /// ```
1685    pub const fn jmp_ifx(
1686        left_reg: Register,
1687        operation: JumpOperation,
1688        right_reg: Register,
1689        offset: i16,
1690    ) -> Self {
1691        let opcode = Opcode::Jump(JumpOpcode {
1692            class: OpcodeClass::Jump,
1693            source: SourceOperand::Register,
1694            operation,
1695        });
1696
1697        Self {
1698            opcode,
1699            dst_reg: left_reg,
1700            src_reg: right_reg,
1701            offset,
1702            imm: 0,
1703        }
1704    }
1705
1706    /// Helper function for creating control-flow instructions.
1707    ///
1708    /// # Arguments
1709    ///
1710    /// * `left_reg` - The register on the left side of the operation.
1711    /// * `operation` - The operation.
1712    /// * `right_imm` - The value on the right side of the operation.
1713    /// * `offset` - The offset to jump to, if true.
1714    ///
1715    /// # Example
1716    /// ```
1717    /// use bpf_ins::{Instruction, JumpOperation, Register};
1718    ///
1719    /// let instruction = Instruction::jmp_if(Register::R1, JumpOperation::IfGreater, 0, 5);
1720    /// ```
1721    pub const fn jmp_if(
1722        left_reg: Register,
1723        operation: JumpOperation,
1724        right_imm: i64,
1725        offset: i16,
1726    ) -> Self {
1727        let opcode = Opcode::Jump(JumpOpcode {
1728            class: OpcodeClass::Jump,
1729            source: SourceOperand::Immediate,
1730            operation,
1731        });
1732
1733        Self {
1734            opcode,
1735            dst_reg: left_reg,
1736            src_reg: Register::R0,
1737            offset,
1738            imm: right_imm,
1739        }
1740    }
1741
1742    /// Helper function for creating an absolute jump instruction.
1743    ///
1744    /// # Arguments
1745    ///
1746    /// * `offset` - The absolute jump offset.
1747    ///
1748    /// # Example
1749    /// ```
1750    /// use bpf_ins::{Instruction};
1751    ///
1752    /// let instruction = Instruction::jmp_abs(5);
1753    /// ```
1754    pub const fn jmp_abs(offset: i16) -> Self {
1755        let opcode = Opcode::Jump(JumpOpcode {
1756            class: OpcodeClass::Jump,
1757            source: SourceOperand::Immediate,
1758            operation: JumpOperation::Absolute,
1759        });
1760
1761        Self {
1762            opcode,
1763            dst_reg: Register::R0,
1764            src_reg: Register::R0,
1765            offset,
1766            imm: 0,
1767        }
1768    }
1769
1770    /// Helper function for creating instructions that call eBPF helpers.
1771    ///
1772    /// # Arguments
1773    ///
1774    /// * `n` - The number of the helper function to call.
1775    ///
1776    /// # Example
1777    /// ```
1778    /// use bpf_ins::{Instruction};
1779    /// const PROBE_WRITE_USER_NUM: u32 = 36;
1780    ///
1781    /// let instruction = Instruction::call(PROBE_WRITE_USER_NUM);
1782    /// assert_eq!(instruction.encode(), (0x2400000085, None));
1783    /// ```
1784    pub const fn call(n: u32) -> Self {
1785        let opcode = Opcode::Jump(JumpOpcode {
1786            class: OpcodeClass::Jump,
1787            source: SourceOperand::Immediate,
1788            operation: JumpOperation::Call,
1789        });
1790
1791        Self {
1792            opcode,
1793            dst_reg: Register::R0,
1794            src_reg: Register::R0,
1795            offset: 0,
1796            imm: n as i64,
1797        }
1798    }
1799
1800    /// Helper function for creating an exit instruction.
1801    ///
1802    /// # Example
1803    /// ```
1804    /// use bpf_ins::{Instruction};
1805    ///
1806    /// let instruction = Instruction::exit();
1807    /// assert_eq!(instruction.encode(), (0x95, None));
1808    /// ```
1809    pub const fn exit() -> Self {
1810        let opcode = Opcode::Jump(JumpOpcode {
1811            class: OpcodeClass::Jump,
1812            source: SourceOperand::Immediate,
1813            operation: JumpOperation::Exit,
1814        });
1815
1816        Self {
1817            opcode,
1818            dst_reg: Register::R0,
1819            src_reg: Register::R0,
1820            offset: 0,
1821            imm: 0,
1822        }
1823    }
1824}