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