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}