xref: /DragonOS/kernel/crates/rbpf/src/ebpf.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2*fae6e9adSlinfeng // Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
3*fae6e9adSlinfeng 
4*fae6e9adSlinfeng //! This module contains all the definitions related to eBPF, and some functions permitting to
5*fae6e9adSlinfeng //! manipulate eBPF instructions.
6*fae6e9adSlinfeng //!
7*fae6e9adSlinfeng //! The number of bytes in an instruction, the maximum number of instructions in a program, and
8*fae6e9adSlinfeng //! also all operation codes are defined here as constants.
9*fae6e9adSlinfeng //!
10*fae6e9adSlinfeng //! The structure for an instruction used by this crate, as well as the function to extract it from
11*fae6e9adSlinfeng //! a program, is also defined in the module.
12*fae6e9adSlinfeng //!
13*fae6e9adSlinfeng //! To learn more about these instructions, see the Linux kernel documentation:
14*fae6e9adSlinfeng //! <https://www.kernel.org/doc/Documentation/networking/filter.txt>, or for a shorter version of
15*fae6e9adSlinfeng //! the list of the operation codes: <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md>
16*fae6e9adSlinfeng 
17*fae6e9adSlinfeng use alloc::{vec, vec::Vec};
18*fae6e9adSlinfeng 
19*fae6e9adSlinfeng use byteorder::{ByteOrder, LittleEndian};
20*fae6e9adSlinfeng 
21*fae6e9adSlinfeng /// The maximum call depth is 8
22*fae6e9adSlinfeng pub const RBPF_MAX_CALL_DEPTH: usize = 8;
23*fae6e9adSlinfeng 
24*fae6e9adSlinfeng /// Maximum number of instructions in an eBPF program.
25*fae6e9adSlinfeng pub const PROG_MAX_INSNS: usize = 1000000;
26*fae6e9adSlinfeng /// Size of an eBPF instructions, in bytes.
27*fae6e9adSlinfeng pub const INSN_SIZE: usize = 8;
28*fae6e9adSlinfeng /// Maximum size of an eBPF program, in bytes.
29*fae6e9adSlinfeng pub const PROG_MAX_SIZE: usize = PROG_MAX_INSNS * INSN_SIZE;
30*fae6e9adSlinfeng /// Stack for the eBPF stack, in bytes.
31*fae6e9adSlinfeng pub const STACK_SIZE: usize = 512;
32*fae6e9adSlinfeng 
33*fae6e9adSlinfeng // eBPF op codes.
34*fae6e9adSlinfeng // See also https://www.kernel.org/doc/Documentation/networking/filter.txt
35*fae6e9adSlinfeng 
36*fae6e9adSlinfeng // Three least significant bits are operation class:
37*fae6e9adSlinfeng /// BPF operation class: load from immediate.
38*fae6e9adSlinfeng pub const BPF_LD: u8 = 0x00;
39*fae6e9adSlinfeng /// BPF operation class: load from register.
40*fae6e9adSlinfeng pub const BPF_LDX: u8 = 0x01;
41*fae6e9adSlinfeng /// BPF operation class: store immediate.
42*fae6e9adSlinfeng pub const BPF_ST: u8 = 0x02;
43*fae6e9adSlinfeng /// BPF operation class: store value from register.
44*fae6e9adSlinfeng pub const BPF_STX: u8 = 0x03;
45*fae6e9adSlinfeng /// BPF operation class: 32 bits arithmetic operation.
46*fae6e9adSlinfeng pub const BPF_ALU: u8 = 0x04;
47*fae6e9adSlinfeng /// BPF operation class: jump (64-bit wide operands for comparisons).
48*fae6e9adSlinfeng pub const BPF_JMP: u8 = 0x05;
49*fae6e9adSlinfeng /// BPF operation class: jump (32-bit wide operands for comparisons).
50*fae6e9adSlinfeng pub const BPF_JMP32: u8 = 0x06;
51*fae6e9adSlinfeng // [ class 6 unused, reserved for future use ]
52*fae6e9adSlinfeng /// BPF operation class: 64 bits arithmetic operation.
53*fae6e9adSlinfeng pub const BPF_ALU64: u8 = 0x07;
54*fae6e9adSlinfeng 
55*fae6e9adSlinfeng // For load and store instructions:
56*fae6e9adSlinfeng // +------------+--------+------------+
57*fae6e9adSlinfeng // |   3 bits   | 2 bits |   3 bits   |
58*fae6e9adSlinfeng // |    mode    |  size  | insn class |
59*fae6e9adSlinfeng // +------------+--------+------------+
60*fae6e9adSlinfeng // (MSB)                          (LSB)
61*fae6e9adSlinfeng 
62*fae6e9adSlinfeng // Size modifiers:
63*fae6e9adSlinfeng /// BPF size modifier: word (4 bytes).
64*fae6e9adSlinfeng pub const BPF_W: u8 = 0x00;
65*fae6e9adSlinfeng /// BPF size modifier: half-word (2 bytes).
66*fae6e9adSlinfeng pub const BPF_H: u8 = 0x08;
67*fae6e9adSlinfeng /// BPF size modifier: byte (1 byte).
68*fae6e9adSlinfeng pub const BPF_B: u8 = 0x10;
69*fae6e9adSlinfeng /// BPF size modifier: double word (8 bytes).
70*fae6e9adSlinfeng pub const BPF_DW: u8 = 0x18;
71*fae6e9adSlinfeng 
72*fae6e9adSlinfeng // Mode modifiers:
73*fae6e9adSlinfeng /// BPF mode modifier: immediate value.
74*fae6e9adSlinfeng pub const BPF_IMM: u8 = 0x00;
75*fae6e9adSlinfeng /// BPF mode modifier: absolute load.
76*fae6e9adSlinfeng pub const BPF_ABS: u8 = 0x20;
77*fae6e9adSlinfeng /// BPF mode modifier: indirect load.
78*fae6e9adSlinfeng pub const BPF_IND: u8 = 0x40;
79*fae6e9adSlinfeng /// BPF mode modifier: load from / store to memory.
80*fae6e9adSlinfeng pub const BPF_MEM: u8 = 0x60;
81*fae6e9adSlinfeng // [ 0x80 reserved ]
82*fae6e9adSlinfeng // [ 0xa0 reserved ]
83*fae6e9adSlinfeng /// BPF mode modifier: exclusive add.
84*fae6e9adSlinfeng pub const BPF_XADD: u8 = 0xc0;
85*fae6e9adSlinfeng 
86*fae6e9adSlinfeng // For arithmetic (BPF_ALU/BPF_ALU64) and jump (BPF_JMP) instructions:
87*fae6e9adSlinfeng // +----------------+--------+--------+
88*fae6e9adSlinfeng // |     4 bits     |1 b.|   3 bits   |
89*fae6e9adSlinfeng // | operation code | src| insn class |
90*fae6e9adSlinfeng // +----------------+----+------------+
91*fae6e9adSlinfeng // (MSB)                          (LSB)
92*fae6e9adSlinfeng 
93*fae6e9adSlinfeng // Source modifiers:
94*fae6e9adSlinfeng /// BPF source operand modifier: 32-bit immediate value.
95*fae6e9adSlinfeng pub const BPF_K: u8 = 0x00;
96*fae6e9adSlinfeng /// BPF source operand modifier: `src` register.
97*fae6e9adSlinfeng pub const BPF_X: u8 = 0x08;
98*fae6e9adSlinfeng 
99*fae6e9adSlinfeng // Operation codes -- BPF_ALU or BPF_ALU64 classes:
100*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: addition.
101*fae6e9adSlinfeng pub const BPF_ADD: u8 = 0x00;
102*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: subtraction.
103*fae6e9adSlinfeng pub const BPF_SUB: u8 = 0x10;
104*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: multiplication.
105*fae6e9adSlinfeng pub const BPF_MUL: u8 = 0x20;
106*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: division.
107*fae6e9adSlinfeng pub const BPF_DIV: u8 = 0x30;
108*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: or.
109*fae6e9adSlinfeng pub const BPF_OR: u8 = 0x40;
110*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: and.
111*fae6e9adSlinfeng pub const BPF_AND: u8 = 0x50;
112*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: left shift.
113*fae6e9adSlinfeng pub const BPF_LSH: u8 = 0x60;
114*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: right shift.
115*fae6e9adSlinfeng pub const BPF_RSH: u8 = 0x70;
116*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: negation.
117*fae6e9adSlinfeng pub const BPF_NEG: u8 = 0x80;
118*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: modulus.
119*fae6e9adSlinfeng pub const BPF_MOD: u8 = 0x90;
120*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: exclusive or.
121*fae6e9adSlinfeng pub const BPF_XOR: u8 = 0xa0;
122*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: move.
123*fae6e9adSlinfeng pub const BPF_MOV: u8 = 0xb0;
124*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: sign extending right shift.
125*fae6e9adSlinfeng pub const BPF_ARSH: u8 = 0xc0;
126*fae6e9adSlinfeng /// BPF ALU/ALU64 operation code: endianness conversion.
127*fae6e9adSlinfeng pub const BPF_END: u8 = 0xd0;
128*fae6e9adSlinfeng 
129*fae6e9adSlinfeng // Operation codes -- BPF_JMP or BPF_JMP32 classes:
130*fae6e9adSlinfeng /// BPF JMP operation code: jump.
131*fae6e9adSlinfeng pub const BPF_JA: u8 = 0x00;
132*fae6e9adSlinfeng /// BPF JMP operation code: jump if equal.
133*fae6e9adSlinfeng pub const BPF_JEQ: u8 = 0x10;
134*fae6e9adSlinfeng /// BPF JMP operation code: jump if greater than.
135*fae6e9adSlinfeng pub const BPF_JGT: u8 = 0x20;
136*fae6e9adSlinfeng /// BPF JMP operation code: jump if greater or equal.
137*fae6e9adSlinfeng pub const BPF_JGE: u8 = 0x30;
138*fae6e9adSlinfeng /// BPF JMP operation code: jump if `src` & `reg`.
139*fae6e9adSlinfeng pub const BPF_JSET: u8 = 0x40;
140*fae6e9adSlinfeng /// BPF JMP operation code: jump if not equal.
141*fae6e9adSlinfeng pub const BPF_JNE: u8 = 0x50;
142*fae6e9adSlinfeng /// BPF JMP operation code: jump if greater than (signed).
143*fae6e9adSlinfeng pub const BPF_JSGT: u8 = 0x60;
144*fae6e9adSlinfeng /// BPF JMP operation code: jump if greater or equal (signed).
145*fae6e9adSlinfeng pub const BPF_JSGE: u8 = 0x70;
146*fae6e9adSlinfeng /// BPF JMP operation code: helper function call.
147*fae6e9adSlinfeng pub const BPF_CALL: u8 = 0x80;
148*fae6e9adSlinfeng /// BPF JMP operation code: return from program.
149*fae6e9adSlinfeng pub const BPF_EXIT: u8 = 0x90;
150*fae6e9adSlinfeng /// BPF JMP operation code: jump if lower than.
151*fae6e9adSlinfeng pub const BPF_JLT: u8 = 0xa0;
152*fae6e9adSlinfeng /// BPF JMP operation code: jump if lower or equal.
153*fae6e9adSlinfeng pub const BPF_JLE: u8 = 0xb0;
154*fae6e9adSlinfeng /// BPF JMP operation code: jump if lower than (signed).
155*fae6e9adSlinfeng pub const BPF_JSLT: u8 = 0xc0;
156*fae6e9adSlinfeng /// BPF JMP operation code: jump if lower or equal (signed).
157*fae6e9adSlinfeng pub const BPF_JSLE: u8 = 0xd0;
158*fae6e9adSlinfeng 
159*fae6e9adSlinfeng // Op codes
160*fae6e9adSlinfeng // (Following operation names are not “official”, but may be proper to rbpf; Linux kernel only
161*fae6e9adSlinfeng // combines above flags and does not attribute a name per operation.)
162*fae6e9adSlinfeng 
163*fae6e9adSlinfeng /// BPF opcode: `ldabsb src, dst, imm`.
164*fae6e9adSlinfeng pub const LD_ABS_B: u8 = BPF_LD | BPF_ABS | BPF_B;
165*fae6e9adSlinfeng /// BPF opcode: `ldabsh src, dst, imm`.
166*fae6e9adSlinfeng pub const LD_ABS_H: u8 = BPF_LD | BPF_ABS | BPF_H;
167*fae6e9adSlinfeng /// BPF opcode: `ldabsw src, dst, imm`.
168*fae6e9adSlinfeng pub const LD_ABS_W: u8 = BPF_LD | BPF_ABS | BPF_W;
169*fae6e9adSlinfeng /// BPF opcode: `ldabsdw src, dst, imm`.
170*fae6e9adSlinfeng pub const LD_ABS_DW: u8 = BPF_LD | BPF_ABS | BPF_DW;
171*fae6e9adSlinfeng /// BPF opcode: `ldindb src, dst, imm`.
172*fae6e9adSlinfeng pub const LD_IND_B: u8 = BPF_LD | BPF_IND | BPF_B;
173*fae6e9adSlinfeng /// BPF opcode: `ldindh src, dst, imm`.
174*fae6e9adSlinfeng pub const LD_IND_H: u8 = BPF_LD | BPF_IND | BPF_H;
175*fae6e9adSlinfeng /// BPF opcode: `ldindw src, dst, imm`.
176*fae6e9adSlinfeng pub const LD_IND_W: u8 = BPF_LD | BPF_IND | BPF_W;
177*fae6e9adSlinfeng /// BPF opcode: `ldinddw src, dst, imm`.
178*fae6e9adSlinfeng pub const LD_IND_DW: u8 = BPF_LD | BPF_IND | BPF_DW;
179*fae6e9adSlinfeng 
180*fae6e9adSlinfeng #[allow(unknown_lints)]
181*fae6e9adSlinfeng #[allow(clippy::eq_op)]
182*fae6e9adSlinfeng /// BPF opcode: `lddw dst, imm` /// `dst = imm`.
183*fae6e9adSlinfeng pub const LD_DW_IMM: u8 = BPF_LD | BPF_IMM | BPF_DW;
184*fae6e9adSlinfeng /// BPF opcode: `ldxb dst, [src + off]` /// `dst = (src + off) as u8`.
185*fae6e9adSlinfeng pub const LD_B_REG: u8 = BPF_LDX | BPF_MEM | BPF_B;
186*fae6e9adSlinfeng /// BPF opcode: `ldxh dst, [src + off]` /// `dst = (src + off) as u16`.
187*fae6e9adSlinfeng pub const LD_H_REG: u8 = BPF_LDX | BPF_MEM | BPF_H;
188*fae6e9adSlinfeng /// BPF opcode: `ldxw dst, [src + off]` /// `dst = (src + off) as u32`.
189*fae6e9adSlinfeng pub const LD_W_REG: u8 = BPF_LDX | BPF_MEM | BPF_W;
190*fae6e9adSlinfeng /// BPF opcode: `ldxdw dst, [src + off]` /// `dst = (src + off) as u64`.
191*fae6e9adSlinfeng pub const LD_DW_REG: u8 = BPF_LDX | BPF_MEM | BPF_DW;
192*fae6e9adSlinfeng /// BPF opcode: `stb [dst + off], imm` /// `(dst + offset) as u8 = imm`.
193*fae6e9adSlinfeng pub const ST_B_IMM: u8 = BPF_ST | BPF_MEM | BPF_B;
194*fae6e9adSlinfeng /// BPF opcode: `sth [dst + off], imm` /// `(dst + offset) as u16 = imm`.
195*fae6e9adSlinfeng pub const ST_H_IMM: u8 = BPF_ST | BPF_MEM | BPF_H;
196*fae6e9adSlinfeng /// BPF opcode: `stw [dst + off], imm` /// `(dst + offset) as u32 = imm`.
197*fae6e9adSlinfeng pub const ST_W_IMM: u8 = BPF_ST | BPF_MEM | BPF_W;
198*fae6e9adSlinfeng /// BPF opcode: `stdw [dst + off], imm` /// `(dst + offset) as u64 = imm`.
199*fae6e9adSlinfeng pub const ST_DW_IMM: u8 = BPF_ST | BPF_MEM | BPF_DW;
200*fae6e9adSlinfeng /// BPF opcode: `stxb [dst + off], src` /// `(dst + offset) as u8 = src`.
201*fae6e9adSlinfeng pub const ST_B_REG: u8 = BPF_STX | BPF_MEM | BPF_B;
202*fae6e9adSlinfeng /// BPF opcode: `stxh [dst + off], src` /// `(dst + offset) as u16 = src`.
203*fae6e9adSlinfeng pub const ST_H_REG: u8 = BPF_STX | BPF_MEM | BPF_H;
204*fae6e9adSlinfeng /// BPF opcode: `stxw [dst + off], src` /// `(dst + offset) as u32 = src`.
205*fae6e9adSlinfeng pub const ST_W_REG: u8 = BPF_STX | BPF_MEM | BPF_W;
206*fae6e9adSlinfeng /// BPF opcode: `stxdw [dst + off], src` /// `(dst + offset) as u64 = src`.
207*fae6e9adSlinfeng pub const ST_DW_REG: u8 = BPF_STX | BPF_MEM | BPF_DW;
208*fae6e9adSlinfeng 
209*fae6e9adSlinfeng /// BPF opcode: `stxxaddw [dst + off], src`.
210*fae6e9adSlinfeng pub const ST_W_XADD: u8 = BPF_STX | BPF_XADD | BPF_W;
211*fae6e9adSlinfeng /// BPF opcode: `stxxadddw [dst + off], src`.
212*fae6e9adSlinfeng pub const ST_DW_XADD: u8 = BPF_STX | BPF_XADD | BPF_DW;
213*fae6e9adSlinfeng 
214*fae6e9adSlinfeng /// BPF opcode: `add32 dst, imm` /// `dst += imm`.
215*fae6e9adSlinfeng pub const ADD32_IMM: u8 = BPF_ALU | BPF_K | BPF_ADD;
216*fae6e9adSlinfeng /// BPF opcode: `add32 dst, src` /// `dst += src`.
217*fae6e9adSlinfeng pub const ADD32_REG: u8 = BPF_ALU | BPF_X | BPF_ADD;
218*fae6e9adSlinfeng /// BPF opcode: `sub32 dst, imm` /// `dst -= imm`.
219*fae6e9adSlinfeng pub const SUB32_IMM: u8 = BPF_ALU | BPF_K | BPF_SUB;
220*fae6e9adSlinfeng /// BPF opcode: `sub32 dst, src` /// `dst -= src`.
221*fae6e9adSlinfeng pub const SUB32_REG: u8 = BPF_ALU | BPF_X | BPF_SUB;
222*fae6e9adSlinfeng /// BPF opcode: `mul32 dst, imm` /// `dst *= imm`.
223*fae6e9adSlinfeng pub const MUL32_IMM: u8 = BPF_ALU | BPF_K | BPF_MUL;
224*fae6e9adSlinfeng /// BPF opcode: `mul32 dst, src` /// `dst *= src`.
225*fae6e9adSlinfeng pub const MUL32_REG: u8 = BPF_ALU | BPF_X | BPF_MUL;
226*fae6e9adSlinfeng /// BPF opcode: `div32 dst, imm` /// `dst /= imm`.
227*fae6e9adSlinfeng pub const DIV32_IMM: u8 = BPF_ALU | BPF_K | BPF_DIV;
228*fae6e9adSlinfeng /// BPF opcode: `div32 dst, src` /// `dst /= src`.
229*fae6e9adSlinfeng pub const DIV32_REG: u8 = BPF_ALU | BPF_X | BPF_DIV;
230*fae6e9adSlinfeng /// BPF opcode: `or32 dst, imm` /// `dst |= imm`.
231*fae6e9adSlinfeng pub const OR32_IMM: u8 = BPF_ALU | BPF_K | BPF_OR;
232*fae6e9adSlinfeng /// BPF opcode: `or32 dst, src` /// `dst |= src`.
233*fae6e9adSlinfeng pub const OR32_REG: u8 = BPF_ALU | BPF_X | BPF_OR;
234*fae6e9adSlinfeng /// BPF opcode: `and32 dst, imm` /// `dst &= imm`.
235*fae6e9adSlinfeng pub const AND32_IMM: u8 = BPF_ALU | BPF_K | BPF_AND;
236*fae6e9adSlinfeng /// BPF opcode: `and32 dst, src` /// `dst &= src`.
237*fae6e9adSlinfeng pub const AND32_REG: u8 = BPF_ALU | BPF_X | BPF_AND;
238*fae6e9adSlinfeng /// BPF opcode: `lsh32 dst, imm` /// `dst <<= imm`.
239*fae6e9adSlinfeng pub const LSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_LSH;
240*fae6e9adSlinfeng /// BPF opcode: `lsh32 dst, src` /// `dst <<= src`.
241*fae6e9adSlinfeng pub const LSH32_REG: u8 = BPF_ALU | BPF_X | BPF_LSH;
242*fae6e9adSlinfeng /// BPF opcode: `rsh32 dst, imm` /// `dst >>= imm`.
243*fae6e9adSlinfeng pub const RSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_RSH;
244*fae6e9adSlinfeng /// BPF opcode: `rsh32 dst, src` /// `dst >>= src`.
245*fae6e9adSlinfeng pub const RSH32_REG: u8 = BPF_ALU | BPF_X | BPF_RSH;
246*fae6e9adSlinfeng /// BPF opcode: `neg32 dst` /// `dst = -dst`.
247*fae6e9adSlinfeng pub const NEG32: u8 = BPF_ALU | BPF_NEG;
248*fae6e9adSlinfeng /// BPF opcode: `mod32 dst, imm` /// `dst %= imm`.
249*fae6e9adSlinfeng pub const MOD32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOD;
250*fae6e9adSlinfeng /// BPF opcode: `mod32 dst, src` /// `dst %= src`.
251*fae6e9adSlinfeng pub const MOD32_REG: u8 = BPF_ALU | BPF_X | BPF_MOD;
252*fae6e9adSlinfeng /// BPF opcode: `xor32 dst, imm` /// `dst ^= imm`.
253*fae6e9adSlinfeng pub const XOR32_IMM: u8 = BPF_ALU | BPF_K | BPF_XOR;
254*fae6e9adSlinfeng /// BPF opcode: `xor32 dst, src` /// `dst ^= src`.
255*fae6e9adSlinfeng pub const XOR32_REG: u8 = BPF_ALU | BPF_X | BPF_XOR;
256*fae6e9adSlinfeng /// BPF opcode: `mov32 dst, imm` /// `dst = imm`.
257*fae6e9adSlinfeng pub const MOV32_IMM: u8 = BPF_ALU | BPF_K | BPF_MOV;
258*fae6e9adSlinfeng /// BPF opcode: `mov32 dst, src` /// `dst = src`.
259*fae6e9adSlinfeng pub const MOV32_REG: u8 = BPF_ALU | BPF_X | BPF_MOV;
260*fae6e9adSlinfeng /// BPF opcode: `arsh32 dst, imm` /// `dst >>= imm (arithmetic)`.
261*fae6e9adSlinfeng ///
262*fae6e9adSlinfeng /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
263*fae6e9adSlinfeng pub const ARSH32_IMM: u8 = BPF_ALU | BPF_K | BPF_ARSH;
264*fae6e9adSlinfeng /// BPF opcode: `arsh32 dst, src` /// `dst >>= src (arithmetic)`.
265*fae6e9adSlinfeng ///
266*fae6e9adSlinfeng /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
267*fae6e9adSlinfeng pub const ARSH32_REG: u8 = BPF_ALU | BPF_X | BPF_ARSH;
268*fae6e9adSlinfeng 
269*fae6e9adSlinfeng /// BPF opcode: `le dst` /// `dst = htole<imm>(dst), with imm in {16, 32, 64}`.
270*fae6e9adSlinfeng pub const LE: u8 = BPF_ALU | BPF_K | BPF_END;
271*fae6e9adSlinfeng /// BPF opcode: `be dst` /// `dst = htobe<imm>(dst), with imm in {16, 32, 64}`.
272*fae6e9adSlinfeng pub const BE: u8 = BPF_ALU | BPF_X | BPF_END;
273*fae6e9adSlinfeng 
274*fae6e9adSlinfeng /// BPF opcode: `add64 dst, imm` /// `dst += imm`.
275*fae6e9adSlinfeng pub const ADD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ADD;
276*fae6e9adSlinfeng /// BPF opcode: `add64 dst, src` /// `dst += src`.
277*fae6e9adSlinfeng pub const ADD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ADD;
278*fae6e9adSlinfeng /// BPF opcode: `sub64 dst, imm` /// `dst -= imm`.
279*fae6e9adSlinfeng pub const SUB64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_SUB;
280*fae6e9adSlinfeng /// BPF opcode: `sub64 dst, src` /// `dst -= src`.
281*fae6e9adSlinfeng pub const SUB64_REG: u8 = BPF_ALU64 | BPF_X | BPF_SUB;
282*fae6e9adSlinfeng /// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
283*fae6e9adSlinfeng pub const MUL64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MUL;
284*fae6e9adSlinfeng /// BPF opcode: `div64 dst, src` /// `dst /= src`.
285*fae6e9adSlinfeng pub const MUL64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MUL;
286*fae6e9adSlinfeng /// BPF opcode: `div64 dst, imm` /// `dst /= imm`.
287*fae6e9adSlinfeng pub const DIV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_DIV;
288*fae6e9adSlinfeng /// BPF opcode: `div64 dst, src` /// `dst /= src`.
289*fae6e9adSlinfeng pub const DIV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_DIV;
290*fae6e9adSlinfeng /// BPF opcode: `or64 dst, imm` /// `dst |= imm`.
291*fae6e9adSlinfeng pub const OR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_OR;
292*fae6e9adSlinfeng /// BPF opcode: `or64 dst, src` /// `dst |= src`.
293*fae6e9adSlinfeng pub const OR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_OR;
294*fae6e9adSlinfeng /// BPF opcode: `and64 dst, imm` /// `dst &= imm`.
295*fae6e9adSlinfeng pub const AND64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_AND;
296*fae6e9adSlinfeng /// BPF opcode: `and64 dst, src` /// `dst &= src`.
297*fae6e9adSlinfeng pub const AND64_REG: u8 = BPF_ALU64 | BPF_X | BPF_AND;
298*fae6e9adSlinfeng /// BPF opcode: `lsh64 dst, imm` /// `dst <<= imm`.
299*fae6e9adSlinfeng pub const LSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_LSH;
300*fae6e9adSlinfeng /// BPF opcode: `lsh64 dst, src` /// `dst <<= src`.
301*fae6e9adSlinfeng pub const LSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_LSH;
302*fae6e9adSlinfeng /// BPF opcode: `rsh64 dst, imm` /// `dst >>= imm`.
303*fae6e9adSlinfeng pub const RSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_RSH;
304*fae6e9adSlinfeng /// BPF opcode: `rsh64 dst, src` /// `dst >>= src`.
305*fae6e9adSlinfeng pub const RSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_RSH;
306*fae6e9adSlinfeng /// BPF opcode: `neg64 dst, imm` /// `dst = -dst`.
307*fae6e9adSlinfeng pub const NEG64: u8 = BPF_ALU64 | BPF_NEG;
308*fae6e9adSlinfeng /// BPF opcode: `mod64 dst, imm` /// `dst %= imm`.
309*fae6e9adSlinfeng pub const MOD64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOD;
310*fae6e9adSlinfeng /// BPF opcode: `mod64 dst, src` /// `dst %= src`.
311*fae6e9adSlinfeng pub const MOD64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOD;
312*fae6e9adSlinfeng /// BPF opcode: `xor64 dst, imm` /// `dst ^= imm`.
313*fae6e9adSlinfeng pub const XOR64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_XOR;
314*fae6e9adSlinfeng /// BPF opcode: `xor64 dst, src` /// `dst ^= src`.
315*fae6e9adSlinfeng pub const XOR64_REG: u8 = BPF_ALU64 | BPF_X | BPF_XOR;
316*fae6e9adSlinfeng /// BPF opcode: `mov64 dst, imm` /// `dst = imm`.
317*fae6e9adSlinfeng pub const MOV64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_MOV;
318*fae6e9adSlinfeng /// BPF opcode: `mov64 dst, src` /// `dst = src`.
319*fae6e9adSlinfeng pub const MOV64_REG: u8 = BPF_ALU64 | BPF_X | BPF_MOV;
320*fae6e9adSlinfeng /// BPF opcode: `arsh64 dst, imm` /// `dst >>= imm (arithmetic)`.
321*fae6e9adSlinfeng ///
322*fae6e9adSlinfeng /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
323*fae6e9adSlinfeng pub const ARSH64_IMM: u8 = BPF_ALU64 | BPF_K | BPF_ARSH;
324*fae6e9adSlinfeng /// BPF opcode: `arsh64 dst, src` /// `dst >>= src (arithmetic)`.
325*fae6e9adSlinfeng ///
326*fae6e9adSlinfeng /// <https://en.wikipedia.org/wiki/Arithmetic_shift>
327*fae6e9adSlinfeng pub const ARSH64_REG: u8 = BPF_ALU64 | BPF_X | BPF_ARSH;
328*fae6e9adSlinfeng 
329*fae6e9adSlinfeng /// BPF opcode: `ja +off` /// `PC += off`.
330*fae6e9adSlinfeng pub const JA: u8 = BPF_JMP | BPF_JA;
331*fae6e9adSlinfeng /// BPF opcode: `jeq dst, imm, +off` /// `PC += off if dst == imm`.
332*fae6e9adSlinfeng pub const JEQ_IMM: u8 = BPF_JMP | BPF_K | BPF_JEQ;
333*fae6e9adSlinfeng /// BPF opcode: `jeq dst, src, +off` /// `PC += off if dst == src`.
334*fae6e9adSlinfeng pub const JEQ_REG: u8 = BPF_JMP | BPF_X | BPF_JEQ;
335*fae6e9adSlinfeng /// BPF opcode: `jgt dst, imm, +off` /// `PC += off if dst > imm`.
336*fae6e9adSlinfeng pub const JGT_IMM: u8 = BPF_JMP | BPF_K | BPF_JGT;
337*fae6e9adSlinfeng /// BPF opcode: `jgt dst, src, +off` /// `PC += off if dst > src`.
338*fae6e9adSlinfeng pub const JGT_REG: u8 = BPF_JMP | BPF_X | BPF_JGT;
339*fae6e9adSlinfeng /// BPF opcode: `jge dst, imm, +off` /// `PC += off if dst >= imm`.
340*fae6e9adSlinfeng pub const JGE_IMM: u8 = BPF_JMP | BPF_K | BPF_JGE;
341*fae6e9adSlinfeng /// BPF opcode: `jge dst, src, +off` /// `PC += off if dst >= src`.
342*fae6e9adSlinfeng pub const JGE_REG: u8 = BPF_JMP | BPF_X | BPF_JGE;
343*fae6e9adSlinfeng /// BPF opcode: `jlt dst, imm, +off` /// `PC += off if dst < imm`.
344*fae6e9adSlinfeng pub const JLT_IMM: u8 = BPF_JMP | BPF_K | BPF_JLT;
345*fae6e9adSlinfeng /// BPF opcode: `jlt dst, src, +off` /// `PC += off if dst < src`.
346*fae6e9adSlinfeng pub const JLT_REG: u8 = BPF_JMP | BPF_X | BPF_JLT;
347*fae6e9adSlinfeng /// BPF opcode: `jle dst, imm, +off` /// `PC += off if dst <= imm`.
348*fae6e9adSlinfeng pub const JLE_IMM: u8 = BPF_JMP | BPF_K | BPF_JLE;
349*fae6e9adSlinfeng /// BPF opcode: `jle dst, src, +off` /// `PC += off if dst <= src`.
350*fae6e9adSlinfeng pub const JLE_REG: u8 = BPF_JMP | BPF_X | BPF_JLE;
351*fae6e9adSlinfeng /// BPF opcode: `jset dst, imm, +off` /// `PC += off if dst & imm`.
352*fae6e9adSlinfeng pub const JSET_IMM: u8 = BPF_JMP | BPF_K | BPF_JSET;
353*fae6e9adSlinfeng /// BPF opcode: `jset dst, src, +off` /// `PC += off if dst & src`.
354*fae6e9adSlinfeng pub const JSET_REG: u8 = BPF_JMP | BPF_X | BPF_JSET;
355*fae6e9adSlinfeng /// BPF opcode: `jne dst, imm, +off` /// `PC += off if dst != imm`.
356*fae6e9adSlinfeng pub const JNE_IMM: u8 = BPF_JMP | BPF_K | BPF_JNE;
357*fae6e9adSlinfeng /// BPF opcode: `jne dst, src, +off` /// `PC += off if dst != src`.
358*fae6e9adSlinfeng pub const JNE_REG: u8 = BPF_JMP | BPF_X | BPF_JNE;
359*fae6e9adSlinfeng /// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if dst > imm (signed)`.
360*fae6e9adSlinfeng pub const JSGT_IMM: u8 = BPF_JMP | BPF_K | BPF_JSGT;
361*fae6e9adSlinfeng /// BPF opcode: `jsgt dst, src, +off` /// `PC += off if dst > src (signed)`.
362*fae6e9adSlinfeng pub const JSGT_REG: u8 = BPF_JMP | BPF_X | BPF_JSGT;
363*fae6e9adSlinfeng /// BPF opcode: `jsge dst, imm, +off` /// `PC += off if dst >= imm (signed)`.
364*fae6e9adSlinfeng pub const JSGE_IMM: u8 = BPF_JMP | BPF_K | BPF_JSGE;
365*fae6e9adSlinfeng /// BPF opcode: `jsge dst, src, +off` /// `PC += off if dst >= src (signed)`.
366*fae6e9adSlinfeng pub const JSGE_REG: u8 = BPF_JMP | BPF_X | BPF_JSGE;
367*fae6e9adSlinfeng /// BPF opcode: `jslt dst, imm, +off` /// `PC += off if dst < imm (signed)`.
368*fae6e9adSlinfeng pub const JSLT_IMM: u8 = BPF_JMP | BPF_K | BPF_JSLT;
369*fae6e9adSlinfeng /// BPF opcode: `jslt dst, src, +off` /// `PC += off if dst < src (signed)`.
370*fae6e9adSlinfeng pub const JSLT_REG: u8 = BPF_JMP | BPF_X | BPF_JSLT;
371*fae6e9adSlinfeng /// BPF opcode: `jsle dst, imm, +off` /// `PC += off if dst <= imm (signed)`.
372*fae6e9adSlinfeng pub const JSLE_IMM: u8 = BPF_JMP | BPF_K | BPF_JSLE;
373*fae6e9adSlinfeng /// BPF opcode: `jsle dst, src, +off` /// `PC += off if dst <= src (signed)`.
374*fae6e9adSlinfeng pub const JSLE_REG: u8 = BPF_JMP | BPF_X | BPF_JSLE;
375*fae6e9adSlinfeng 
376*fae6e9adSlinfeng /// BPF opcode: `jeq dst, imm, +off` /// `PC += off if (dst as u32) == imm`.
377*fae6e9adSlinfeng pub const JEQ_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JEQ;
378*fae6e9adSlinfeng /// BPF opcode: `jeq dst, src, +off` /// `PC += off if (dst as u32) == (src as u32)`.
379*fae6e9adSlinfeng pub const JEQ_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JEQ;
380*fae6e9adSlinfeng /// BPF opcode: `jgt dst, imm, +off` /// `PC += off if (dst as u32) > imm`.
381*fae6e9adSlinfeng pub const JGT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JGT;
382*fae6e9adSlinfeng /// BPF opcode: `jgt dst, src, +off` /// `PC += off if (dst as u32) > (src as u32)`.
383*fae6e9adSlinfeng pub const JGT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JGT;
384*fae6e9adSlinfeng /// BPF opcode: `jge dst, imm, +off` /// `PC += off if (dst as u32) >= imm`.
385*fae6e9adSlinfeng pub const JGE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JGE;
386*fae6e9adSlinfeng /// BPF opcode: `jge dst, src, +off` /// `PC += off if (dst as u32) >= (src as u32)`.
387*fae6e9adSlinfeng pub const JGE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JGE;
388*fae6e9adSlinfeng /// BPF opcode: `jlt dst, imm, +off` /// `PC += off if (dst as u32) < imm`.
389*fae6e9adSlinfeng pub const JLT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JLT;
390*fae6e9adSlinfeng /// BPF opcode: `jlt dst, src, +off` /// `PC += off if (dst as u32) < (src as u32)`.
391*fae6e9adSlinfeng pub const JLT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JLT;
392*fae6e9adSlinfeng /// BPF opcode: `jle dst, imm, +off` /// `PC += off if (dst as u32) <= imm`.
393*fae6e9adSlinfeng pub const JLE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JLE;
394*fae6e9adSlinfeng /// BPF opcode: `jle dst, src, +off` /// `PC += off if (dst as u32) <= (src as u32)`.
395*fae6e9adSlinfeng pub const JLE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JLE;
396*fae6e9adSlinfeng /// BPF opcode: `jset dst, imm, +off` /// `PC += off if (dst as u32) & imm`.
397*fae6e9adSlinfeng pub const JSET_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSET;
398*fae6e9adSlinfeng /// BPF opcode: `jset dst, src, +off` /// `PC += off if (dst as u32) & (src as u32)`.
399*fae6e9adSlinfeng pub const JSET_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSET;
400*fae6e9adSlinfeng /// BPF opcode: `jne dst, imm, +off` /// `PC += off if (dst as u32) != imm`.
401*fae6e9adSlinfeng pub const JNE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JNE;
402*fae6e9adSlinfeng /// BPF opcode: `jne dst, src, +off` /// `PC += off if (dst as u32) != (src as u32)`.
403*fae6e9adSlinfeng pub const JNE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JNE;
404*fae6e9adSlinfeng /// BPF opcode: `jsgt dst, imm, +off` /// `PC += off if (dst as i32) > imm (signed)`.
405*fae6e9adSlinfeng pub const JSGT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSGT;
406*fae6e9adSlinfeng /// BPF opcode: `jsgt dst, src, +off` /// `PC += off if (dst as i32) > (src as i32) (signed)`.
407*fae6e9adSlinfeng pub const JSGT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSGT;
408*fae6e9adSlinfeng /// BPF opcode: `jsge dst, imm, +off` /// `PC += off if (dst as i32) >= imm (signed)`.
409*fae6e9adSlinfeng pub const JSGE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSGE;
410*fae6e9adSlinfeng /// BPF opcode: `jsge dst, src, +off` /// `PC += off if (dst as i32) >= (src as i32) (signed)`.
411*fae6e9adSlinfeng pub const JSGE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSGE;
412*fae6e9adSlinfeng /// BPF opcode: `jslt dst, imm, +off` /// `PC += off if (dst as i32) < imm (signed)`.
413*fae6e9adSlinfeng pub const JSLT_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSLT;
414*fae6e9adSlinfeng /// BPF opcode: `jslt dst, src, +off` /// `PC += off if (dst as i32) < (src as i32) (signed)`.
415*fae6e9adSlinfeng pub const JSLT_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSLT;
416*fae6e9adSlinfeng /// BPF opcode: `jsle dst, imm, +off` /// `PC += off if (dst as i32) <= imm (signed)`.
417*fae6e9adSlinfeng pub const JSLE_IMM32: u8 = BPF_JMP32 | BPF_K | BPF_JSLE;
418*fae6e9adSlinfeng /// BPF opcode: `jsle dst, src, +off` /// `PC += off if (dst as i32) <= (src as i32) (signed)`.
419*fae6e9adSlinfeng pub const JSLE_REG32: u8 = BPF_JMP32 | BPF_X | BPF_JSLE;
420*fae6e9adSlinfeng 
421*fae6e9adSlinfeng /// BPF opcode: `call imm` /// helper function call to helper with key `imm`.
422*fae6e9adSlinfeng pub const CALL: u8 = BPF_JMP | BPF_CALL;
423*fae6e9adSlinfeng /// BPF opcode: tail call.
424*fae6e9adSlinfeng pub const TAIL_CALL: u8 = BPF_JMP | BPF_X | BPF_CALL;
425*fae6e9adSlinfeng /// BPF opcode: `exit` /// `return r0`.
426*fae6e9adSlinfeng pub const EXIT: u8 = BPF_JMP | BPF_EXIT;
427*fae6e9adSlinfeng 
428*fae6e9adSlinfeng // Used in JIT
429*fae6e9adSlinfeng /// Mask to extract the operation class from an operation code.
430*fae6e9adSlinfeng pub const BPF_CLS_MASK: u8 = 0x07;
431*fae6e9adSlinfeng /// Mask to extract the arithmetic operation code from an instruction operation code.
432*fae6e9adSlinfeng pub const BPF_ALU_OP_MASK: u8 = 0xf0;
433*fae6e9adSlinfeng 
434*fae6e9adSlinfeng /// Prototype of an eBPF helper function.
435*fae6e9adSlinfeng pub type Helper = fn(u64, u64, u64, u64, u64) -> u64;
436*fae6e9adSlinfeng 
437*fae6e9adSlinfeng /// An eBPF instruction.
438*fae6e9adSlinfeng ///
439*fae6e9adSlinfeng /// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
440*fae6e9adSlinfeng /// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
441*fae6e9adSlinfeng /// more concise version.
442*fae6e9adSlinfeng #[derive(Debug, PartialEq, Eq, Clone)]
443*fae6e9adSlinfeng pub struct Insn {
444*fae6e9adSlinfeng     /// Operation code.
445*fae6e9adSlinfeng     pub opc: u8,
446*fae6e9adSlinfeng     /// Destination register operand.
447*fae6e9adSlinfeng     pub dst: u8,
448*fae6e9adSlinfeng     /// Source register operand.
449*fae6e9adSlinfeng     pub src: u8,
450*fae6e9adSlinfeng     /// Offset operand.
451*fae6e9adSlinfeng     pub off: i16,
452*fae6e9adSlinfeng     /// Immediate value operand.
453*fae6e9adSlinfeng     pub imm: i32,
454*fae6e9adSlinfeng }
455*fae6e9adSlinfeng 
456*fae6e9adSlinfeng impl Insn {
457*fae6e9adSlinfeng     /// Turn an `Insn` back into an array of bytes.
458*fae6e9adSlinfeng     ///
459*fae6e9adSlinfeng     /// # Examples
460*fae6e9adSlinfeng     ///
461*fae6e9adSlinfeng     /// ```
462*fae6e9adSlinfeng     /// use rbpf::ebpf;
463*fae6e9adSlinfeng     ///
464*fae6e9adSlinfeng     /// let prog: &[u8] = &[
465*fae6e9adSlinfeng     ///     0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
466*fae6e9adSlinfeng     ///     ];
467*fae6e9adSlinfeng     /// let insn = ebpf::Insn {
468*fae6e9adSlinfeng     ///     opc: 0xb7,
469*fae6e9adSlinfeng     ///     dst: 2,
470*fae6e9adSlinfeng     ///     src: 1,
471*fae6e9adSlinfeng     ///     off: 0x3456,
472*fae6e9adSlinfeng     ///     imm: 0x789abcde
473*fae6e9adSlinfeng     /// };
474*fae6e9adSlinfeng     /// assert_eq!(insn.to_array(), prog);
475*fae6e9adSlinfeng     /// ```
to_array(&self) -> [u8; INSN_SIZE]476*fae6e9adSlinfeng     pub fn to_array(&self) -> [u8; INSN_SIZE] {
477*fae6e9adSlinfeng         [
478*fae6e9adSlinfeng             self.opc,
479*fae6e9adSlinfeng             self.src.wrapping_shl(4) | self.dst,
480*fae6e9adSlinfeng             (self.off & 0xff) as u8,
481*fae6e9adSlinfeng             self.off.wrapping_shr(8) as u8,
482*fae6e9adSlinfeng             (self.imm & 0xff) as u8,
483*fae6e9adSlinfeng             (self.imm & 0xff_00).wrapping_shr(8) as u8,
484*fae6e9adSlinfeng             (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
485*fae6e9adSlinfeng             (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
486*fae6e9adSlinfeng         ]
487*fae6e9adSlinfeng     }
488*fae6e9adSlinfeng 
489*fae6e9adSlinfeng     /// Turn an `Insn` into an vector of bytes.
490*fae6e9adSlinfeng     ///
491*fae6e9adSlinfeng     /// # Examples
492*fae6e9adSlinfeng     ///
493*fae6e9adSlinfeng     /// ```
494*fae6e9adSlinfeng     /// use rbpf::ebpf;
495*fae6e9adSlinfeng     ///
496*fae6e9adSlinfeng     /// let prog: Vec<u8> = vec![
497*fae6e9adSlinfeng     ///     0xb7, 0x12, 0x56, 0x34, 0xde, 0xbc, 0x9a, 0x78,
498*fae6e9adSlinfeng     ///     ];
499*fae6e9adSlinfeng     /// let insn = ebpf::Insn {
500*fae6e9adSlinfeng     ///     opc: 0xb7,
501*fae6e9adSlinfeng     ///     dst: 2,
502*fae6e9adSlinfeng     ///     src: 1,
503*fae6e9adSlinfeng     ///     off: 0x3456,
504*fae6e9adSlinfeng     ///     imm: 0x789abcde
505*fae6e9adSlinfeng     /// };
506*fae6e9adSlinfeng     /// assert_eq!(insn.to_vec(), prog);
507*fae6e9adSlinfeng     /// ```
to_vec(&self) -> Vec<u8>508*fae6e9adSlinfeng     pub fn to_vec(&self) -> Vec<u8> {
509*fae6e9adSlinfeng         vec![
510*fae6e9adSlinfeng             self.opc,
511*fae6e9adSlinfeng             self.src.wrapping_shl(4) | self.dst,
512*fae6e9adSlinfeng             (self.off & 0xff) as u8,
513*fae6e9adSlinfeng             self.off.wrapping_shr(8) as u8,
514*fae6e9adSlinfeng             (self.imm & 0xff) as u8,
515*fae6e9adSlinfeng             (self.imm & 0xff_00).wrapping_shr(8) as u8,
516*fae6e9adSlinfeng             (self.imm as u32 & 0xff_00_00).wrapping_shr(16) as u8,
517*fae6e9adSlinfeng             (self.imm as u32 & 0xff_00_00_00).wrapping_shr(24) as u8,
518*fae6e9adSlinfeng         ]
519*fae6e9adSlinfeng     }
520*fae6e9adSlinfeng }
521*fae6e9adSlinfeng 
522*fae6e9adSlinfeng /// Get the instruction at `idx` of an eBPF program. `idx` is the index (number) of the
523*fae6e9adSlinfeng /// instruction (not a byte offset). The first instruction has index 0.
524*fae6e9adSlinfeng ///
525*fae6e9adSlinfeng /// # Panics
526*fae6e9adSlinfeng ///
527*fae6e9adSlinfeng /// Panics if it is not possible to get the instruction (if idx is too high, or last instruction is
528*fae6e9adSlinfeng /// incomplete).
529*fae6e9adSlinfeng ///
530*fae6e9adSlinfeng /// # Examples
531*fae6e9adSlinfeng ///
532*fae6e9adSlinfeng /// ```
533*fae6e9adSlinfeng /// use rbpf::ebpf;
534*fae6e9adSlinfeng ///
535*fae6e9adSlinfeng /// let prog = &[
536*fae6e9adSlinfeng ///     0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537*fae6e9adSlinfeng ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
538*fae6e9adSlinfeng ///     ];
539*fae6e9adSlinfeng /// let insn = ebpf::get_insn(prog, 1);
540*fae6e9adSlinfeng /// assert_eq!(insn.opc, 0x95);
541*fae6e9adSlinfeng /// ```
542*fae6e9adSlinfeng ///
543*fae6e9adSlinfeng /// The example below will panic, since the last instruction is not complete and cannot be loaded.
544*fae6e9adSlinfeng ///
545*fae6e9adSlinfeng /// ```rust,should_panic
546*fae6e9adSlinfeng /// use rbpf::ebpf;
547*fae6e9adSlinfeng ///
548*fae6e9adSlinfeng /// let prog = &[
549*fae6e9adSlinfeng ///     0xb7, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
550*fae6e9adSlinfeng ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00              // two bytes missing
551*fae6e9adSlinfeng ///     ];
552*fae6e9adSlinfeng /// let insn = ebpf::get_insn(prog, 1);
553*fae6e9adSlinfeng /// ```
get_insn(prog: &[u8], idx: usize) -> Insn554*fae6e9adSlinfeng pub fn get_insn(prog: &[u8], idx: usize) -> Insn {
555*fae6e9adSlinfeng     // This guard should not be needed in most cases, since the verifier already checks the program
556*fae6e9adSlinfeng     // size, and indexes should be fine in the interpreter/JIT. But this function is publicly
557*fae6e9adSlinfeng     // available and user can call it with any `idx`, so we have to check anyway.
558*fae6e9adSlinfeng     if (idx + 1) * INSN_SIZE > prog.len() {
559*fae6e9adSlinfeng         panic!(
560*fae6e9adSlinfeng             "Error: cannot reach instruction at index {:?} in program containing {:?} bytes",
561*fae6e9adSlinfeng             idx,
562*fae6e9adSlinfeng             prog.len()
563*fae6e9adSlinfeng         );
564*fae6e9adSlinfeng     }
565*fae6e9adSlinfeng     Insn {
566*fae6e9adSlinfeng         opc: prog[INSN_SIZE * idx],
567*fae6e9adSlinfeng         dst: prog[INSN_SIZE * idx + 1] & 0x0f,
568*fae6e9adSlinfeng         src: (prog[INSN_SIZE * idx + 1] & 0xf0) >> 4,
569*fae6e9adSlinfeng         off: LittleEndian::read_i16(&prog[(INSN_SIZE * idx + 2)..]),
570*fae6e9adSlinfeng         imm: LittleEndian::read_i32(&prog[(INSN_SIZE * idx + 4)..]),
571*fae6e9adSlinfeng     }
572*fae6e9adSlinfeng }
573*fae6e9adSlinfeng 
574*fae6e9adSlinfeng /// Return a vector of `struct Insn` built from a program.
575*fae6e9adSlinfeng ///
576*fae6e9adSlinfeng /// This is provided as a convenience for users wishing to manipulate a vector of instructions, for
577*fae6e9adSlinfeng /// example for dumping the program instruction after instruction with a custom format.
578*fae6e9adSlinfeng ///
579*fae6e9adSlinfeng /// Note that the two parts of `LD_DW_IMM` instructions (spanning on 64 bits) are considered as two
580*fae6e9adSlinfeng /// distinct instructions.
581*fae6e9adSlinfeng ///
582*fae6e9adSlinfeng /// # Examples
583*fae6e9adSlinfeng ///
584*fae6e9adSlinfeng /// ```
585*fae6e9adSlinfeng /// use rbpf::ebpf;
586*fae6e9adSlinfeng ///
587*fae6e9adSlinfeng /// let prog = &[
588*fae6e9adSlinfeng ///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
589*fae6e9adSlinfeng ///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
590*fae6e9adSlinfeng ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
591*fae6e9adSlinfeng /// ];
592*fae6e9adSlinfeng ///
593*fae6e9adSlinfeng /// let v = ebpf::to_insn_vec(prog);
594*fae6e9adSlinfeng /// assert_eq!(v, vec![
595*fae6e9adSlinfeng ///     ebpf::Insn {
596*fae6e9adSlinfeng ///         opc: 0x18,
597*fae6e9adSlinfeng ///         dst: 0,
598*fae6e9adSlinfeng ///         src: 0,
599*fae6e9adSlinfeng ///         off: 0,
600*fae6e9adSlinfeng ///         imm: 0x55667788
601*fae6e9adSlinfeng ///     },
602*fae6e9adSlinfeng ///     ebpf::Insn {
603*fae6e9adSlinfeng ///         opc: 0,
604*fae6e9adSlinfeng ///         dst: 0,
605*fae6e9adSlinfeng ///         src: 0,
606*fae6e9adSlinfeng ///         off: 0,
607*fae6e9adSlinfeng ///         imm: 0x11223344
608*fae6e9adSlinfeng ///     },
609*fae6e9adSlinfeng ///     ebpf::Insn {
610*fae6e9adSlinfeng ///         opc: 0x95,
611*fae6e9adSlinfeng ///         dst: 0,
612*fae6e9adSlinfeng ///         src: 0,
613*fae6e9adSlinfeng ///         off: 0,
614*fae6e9adSlinfeng ///         imm: 0
615*fae6e9adSlinfeng ///     },
616*fae6e9adSlinfeng /// ]);
617*fae6e9adSlinfeng /// ```
to_insn_vec(prog: &[u8]) -> Vec<Insn>618*fae6e9adSlinfeng pub fn to_insn_vec(prog: &[u8]) -> Vec<Insn> {
619*fae6e9adSlinfeng     if prog.len() % INSN_SIZE != 0 {
620*fae6e9adSlinfeng         panic!(
621*fae6e9adSlinfeng             "Error: eBPF program length must be a multiple of {:?} octets",
622*fae6e9adSlinfeng             INSN_SIZE
623*fae6e9adSlinfeng         );
624*fae6e9adSlinfeng     }
625*fae6e9adSlinfeng 
626*fae6e9adSlinfeng     let mut res = vec![];
627*fae6e9adSlinfeng     let mut insn_ptr: usize = 0;
628*fae6e9adSlinfeng 
629*fae6e9adSlinfeng     while insn_ptr * INSN_SIZE < prog.len() {
630*fae6e9adSlinfeng         let insn = get_insn(prog, insn_ptr);
631*fae6e9adSlinfeng         res.push(insn);
632*fae6e9adSlinfeng         insn_ptr += 1;
633*fae6e9adSlinfeng     }
634*fae6e9adSlinfeng     res
635*fae6e9adSlinfeng }
636