• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

qmonnet / rbpf / 14940269551

10 May 2025 01:01AM UTC coverage: 95.26% (+0.3%) from 94.957%
14940269551

push

github

qmonnet
rbpf: Apply rustfmt on the whole repository

Let's fix formatting using rustfmt, at last.

    $ rustfmt --version
    rustfmt 1.8.0-nightly (50aa041807 2025-05-08)

    $ rustfmt **/**.rs

Signed-off-by: Quentin Monnet <qmo@qmon.net>

860 of 876 new or added lines in 10 files covered. (98.17%)

60 existing lines in 6 files now uncovered.

4562 of 4789 relevant lines covered (95.26%)

235.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.17
/src/disassembler.rs
1
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2
// Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
3

4
//! Functions in this module are used to handle eBPF programs with a higher level representation,
5
//! for example to disassemble the code into a human-readable format.
6

7
#[cfg(not(feature = "std"))]
8
use log::info;
9
use log::warn;
10

11
use crate::ebpf;
12
use crate::lib::*;
13

14
#[inline]
15
fn alu_imm_str(name: &str, insn: &ebpf::Insn) -> String {
27✔
16
    format!("{name} r{}, {:#x}", insn.dst, insn.imm)
27✔
17
}
27✔
18

19
#[inline]
20
fn alu_reg_str(name: &str, insn: &ebpf::Insn) -> String {
25✔
21
    format!("{name} r{}, r{}", insn.dst, insn.src)
25✔
22
}
25✔
23

24
#[inline]
25
fn byteswap_str(name: &str, insn: &ebpf::Insn) -> String {
7✔
26
    match insn.imm {
7✔
27
        16 | 32 | 64 => {}
7✔
NEW
28
        _ => warn!("[Disassembler] Warning: Invalid offset value for {name} insn"),
×
29
    }
30
    format!("{name}{} r{}", insn.imm, insn.dst)
7✔
31
}
7✔
32

33
#[inline]
34
fn ld_st_imm_str(name: &str, insn: &ebpf::Insn) -> String {
10✔
35
    if insn.off >= 0 {
10✔
36
        format!("{name} [r{}+{:#x}], {:#x}", insn.dst, insn.off, insn.imm)
6✔
37
    } else {
38
        format!(
4✔
39
            "{name} [r{}-{:#x}], {:#x}",
4✔
40
            insn.dst,
41
            -(insn.off as isize),
4✔
42
            insn.imm
43
        )
44
    }
45
}
10✔
46

47
#[inline]
48
fn ld_reg_str(name: &str, insn: &ebpf::Insn) -> String {
10✔
49
    if insn.off >= 0 {
10✔
50
        format!("{name} r{}, [r{}+{:#x}]", insn.dst, insn.src, insn.off)
6✔
51
    } else {
52
        format!(
4✔
53
            "{name} r{}, [r{}-{:#x}]",
4✔
54
            insn.dst,
55
            insn.src,
56
            -(insn.off as isize)
4✔
57
        )
58
    }
59
}
10✔
60

61
#[inline]
62
fn st_reg_str(name: &str, insn: &ebpf::Insn) -> String {
6✔
63
    if insn.off >= 0 {
6✔
64
        format!("{name} [r{}+{:#x}], r{}", insn.dst, insn.off, insn.src)
6✔
65
    } else {
NEW
66
        format!(
×
NEW
67
            "{name} [r{}-{:#x}], r{}",
×
68
            insn.dst,
NEW
69
            -(insn.off as isize),
×
70
            insn.src
71
        )
72
    }
73
}
6✔
74

75
#[inline]
76
fn ldabs_str(name: &str, insn: &ebpf::Insn) -> String {
5✔
77
    format!("{name} {:#x}", insn.imm)
5✔
78
}
5✔
79

80
#[inline]
81
fn ldind_str(name: &str, insn: &ebpf::Insn) -> String {
5✔
82
    format!("{name} r{}, {:#x}", insn.src, insn.imm)
5✔
83
}
5✔
84

85
#[inline]
86
fn jmp_imm_str(name: &str, insn: &ebpf::Insn) -> String {
25✔
87
    if insn.off >= 0 {
25✔
88
        format!("{name} r{}, {:#x}, +{:#x}", insn.dst, insn.imm, insn.off)
19✔
89
    } else {
90
        format!(
6✔
91
            "{name} r{}, {:#x}, -{:#x}",
6✔
92
            insn.dst,
93
            insn.imm,
94
            -(insn.off as isize)
6✔
95
        )
96
    }
97
}
25✔
98

99
#[inline]
100
fn jmp_reg_str(name: &str, insn: &ebpf::Insn) -> String {
25✔
101
    if insn.off >= 0 {
25✔
102
        format!("{name} r{}, r{}, +{:#x}", insn.dst, insn.src, insn.off)
19✔
103
    } else {
104
        format!(
6✔
105
            "{name} r{}, r{}, -{:#x}",
6✔
106
            insn.dst,
107
            insn.src,
108
            -(insn.off as isize)
6✔
109
        )
110
    }
111
}
25✔
112

113
/// High-level representation of an eBPF instruction.
114
///
115
/// In addition to standard operation code and various operand, this struct has the following
116
/// properties:
117
///
118
/// * It stores a name, corresponding to a mnemonic for the operation code.
119
/// * It also stores a description, which is a mnemonic for the full instruction, using the actual
120
///   values of the relevant operands, and that can be used for disassembling the eBPF program for
121
///   example.
122
/// * Immediate values are stored in an `i64` instead of a traditional i32, in order to merge the
123
///   two parts of (otherwise double-length) `LD_DW_IMM` instructions.
124
///
125
/// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
126
/// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
127
/// more concise version.
128
#[derive(Debug, PartialEq, Eq)]
129
pub struct HLInsn {
130
    /// Operation code.
131
    pub opc: u8,
132
    /// Name (mnemonic). This name is not canon.
133
    pub name: String,
134
    /// Description of the instruction. This is not canon.
135
    pub desc: String,
136
    /// Destination register operand.
137
    pub dst: u8,
138
    /// Source register operand.
139
    pub src: u8,
140
    /// Offset operand.
141
    pub off: i16,
142
    /// Immediate value operand. For `LD_DW_IMM` instructions, contains the whole value merged from
143
    /// the two 8-bytes parts of the instruction.
144
    pub imm: i64,
145
}
146

147
/// Return a vector of `struct HLInsn` built from an eBPF program.
148
///
149
/// This is made public to provide a way to manipulate a program as a vector of instructions, in a
150
/// high-level format, for example for dumping the program instruction after instruction with a
151
/// custom format.
152
///
153
/// Note that the two parts of `LD_DW_IMM` instructions (that have the size of two standard
154
/// instructions) are considered as making a single immediate value. As a consequence, the number
155
/// of instructions stored in the vector may not be equal to the size in bytes of the program
156
/// divided by the length of an instructions.
157
///
158
/// To do so, the immediate value operand is stored as an `i64` instead as an i32, so be careful
159
/// when you use it (see example `examples/to_json.rs`).
160
///
161
/// This is to oppose to `ebpf::to_insn_vec()` function, that treats instructions on a low-level
162
/// ground and do not merge the parts of `LD_DW_IMM`. Also, the version in `ebpf` module does not
163
/// use names or descriptions when storing the instructions.
164
///
165
/// # Examples
166
///
167
/// ```
168
/// use rbpf::disassembler;
169
///
170
/// let prog = &[
171
///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
172
///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
173
///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
174
/// ];
175
///
176
/// let v = disassembler::to_insn_vec(prog);
177
/// assert_eq!(v, vec![
178
///     disassembler::HLInsn {
179
///         opc: 0x18,
180
///         name: "lddw".to_string(),
181
///         desc: "lddw r0, 0x1122334455667788".to_string(),
182
///         dst: 0,
183
///         src: 0,
184
///         off: 0,
185
///         imm: 0x1122334455667788
186
///     },
187
///     disassembler::HLInsn {
188
///         opc: 0x95,
189
///         name: "exit".to_string(),
190
///         desc: "exit".to_string(),
191
///         dst: 0,
192
///         src: 0,
193
///         off: 0,
194
///         imm: 0
195
///     },
196
/// ]);
197
/// ```
198
pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
38✔
199
    if prog.len() % ebpf::INSN_SIZE != 0 {
38✔
NEW
200
        panic!(
×
NEW
201
            "[Disassembler] Error: eBPF program length must be a multiple of {:?} octets",
×
202
            ebpf::INSN_SIZE
203
        );
204
    }
38✔
205
    if prog.is_empty() {
38✔
206
        return vec![];
1✔
207
    }
37✔
208

209
    let mut res = vec![];
37✔
210
    let mut insn_ptr: usize = 0;
37✔
211

212
    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
190✔
213
        let insn = ebpf::get_insn(prog, insn_ptr);
153✔
214

215
        let name;
216
        let desc;
217
        let mut imm = insn.imm as i64;
153✔
218
        #[rustfmt::skip]
219
        #[allow(clippy::let_unit_value)] // assign, to avoid #[rustfmt::skip] on an expression
220
        match insn.opc {
153✔
221

222
            // BPF_LD class
223
            ebpf::LD_ABS_B   => { name = "ldabsb";  desc = ldabs_str(name, &insn); },
1✔
224
            ebpf::LD_ABS_H   => { name = "ldabsh";  desc = ldabs_str(name, &insn); },
1✔
225
            ebpf::LD_ABS_W   => { name = "ldabsw";  desc = ldabs_str(name, &insn); },
2✔
226
            ebpf::LD_ABS_DW  => { name = "ldabsdw"; desc = ldabs_str(name, &insn); },
1✔
227
            ebpf::LD_IND_B   => { name = "ldindb";  desc = ldind_str(name, &insn); },
1✔
228
            ebpf::LD_IND_H   => { name = "ldindh";  desc = ldind_str(name, &insn); },
1✔
229
            ebpf::LD_IND_W   => { name = "ldindw";  desc = ldind_str(name, &insn); },
2✔
230
            ebpf::LD_IND_DW  => { name = "ldinddw"; desc = ldind_str(name, &insn); },
1✔
231

232
            ebpf::LD_DW_IMM  => {
2✔
233
                insn_ptr += 1;
2✔
234
                let next_insn = ebpf::get_insn(prog, insn_ptr);
2✔
235
                imm = ((insn.imm as u32) as u64 + ((next_insn.imm as u64) << 32)) as i64;
2✔
236
                name = "lddw"; desc = format!("{name} r{:}, {imm:#x}", insn.dst);
2✔
237
            },
2✔
238

239
            // BPF_LDX class
240
            ebpf::LD_B_REG   => { name = "ldxb";  desc = ld_reg_str(name, &insn); },
2✔
241
            ebpf::LD_H_REG   => { name = "ldxh";  desc = ld_reg_str(name, &insn); },
2✔
242
            ebpf::LD_W_REG   => { name = "ldxw";  desc = ld_reg_str(name, &insn); },
3✔
243
            ebpf::LD_DW_REG  => { name = "ldxdw"; desc = ld_reg_str(name, &insn); },
3✔
244

245
            // BPF_ST class
246
            ebpf::ST_B_IMM   => { name = "stb";  desc = ld_st_imm_str(name, &insn); },
2✔
247
            ebpf::ST_H_IMM   => { name = "sth";  desc = ld_st_imm_str(name, &insn); },
3✔
248
            ebpf::ST_W_IMM   => { name = "stw";  desc = ld_st_imm_str(name, &insn); },
3✔
249
            ebpf::ST_DW_IMM  => { name = "stdw"; desc = ld_st_imm_str(name, &insn); },
2✔
250

251
            // BPF_STX class
252
            ebpf::ST_B_REG   => { name = "stxb";      desc = st_reg_str(name, &insn); },
1✔
253
            ebpf::ST_H_REG   => { name = "stxh";      desc = st_reg_str(name, &insn); },
2✔
254
            ebpf::ST_W_REG   => { name = "stxw";      desc = st_reg_str(name, &insn); },
2✔
255
            ebpf::ST_DW_REG  => { name = "stxdw";     desc = st_reg_str(name, &insn); },
1✔
UNCOV
256
            ebpf::ST_W_XADD  => { name = "stxxaddw";  desc = st_reg_str(name, &insn); },
×
UNCOV
257
            ebpf::ST_DW_XADD => { name = "stxxadddw"; desc = st_reg_str(name, &insn); },
×
258

259
            // BPF_ALU class
260
            ebpf::ADD32_IMM  => { name = "add32";  desc = alu_imm_str(name, &insn);  },
1✔
261
            ebpf::ADD32_REG  => { name = "add32";  desc = alu_reg_str(name, &insn);  },
1✔
262
            ebpf::SUB32_IMM  => { name = "sub32";  desc = alu_imm_str(name, &insn);  },
1✔
263
            ebpf::SUB32_REG  => { name = "sub32";  desc = alu_reg_str(name, &insn);  },
1✔
264
            ebpf::MUL32_IMM  => { name = "mul32";  desc = alu_imm_str(name, &insn);  },
1✔
265
            ebpf::MUL32_REG  => { name = "mul32";  desc = alu_reg_str(name, &insn);  },
1✔
266
            ebpf::DIV32_IMM  => { name = "div32";  desc = alu_imm_str(name, &insn);  },
1✔
267
            ebpf::DIV32_REG  => { name = "div32";  desc = alu_reg_str(name, &insn);  },
1✔
268
            ebpf::OR32_IMM   => { name = "or32";   desc = alu_imm_str(name, &insn);  },
1✔
269
            ebpf::OR32_REG   => { name = "or32";   desc = alu_reg_str(name, &insn);  },
1✔
270
            ebpf::AND32_IMM  => { name = "and32";  desc = alu_imm_str(name, &insn);  },
1✔
271
            ebpf::AND32_REG  => { name = "and32";  desc = alu_reg_str(name, &insn);  },
1✔
272
            ebpf::LSH32_IMM  => { name = "lsh32";  desc = alu_imm_str(name, &insn);  },
1✔
273
            ebpf::LSH32_REG  => { name = "lsh32";  desc = alu_reg_str(name, &insn);  },
1✔
274
            ebpf::RSH32_IMM  => { name = "rsh32";  desc = alu_imm_str(name, &insn);  },
1✔
275
            ebpf::RSH32_REG  => { name = "rsh32";  desc = alu_reg_str(name, &insn);  },
1✔
276
            ebpf::NEG32      => { name = "neg32";  desc = format!("{name} r{:}", insn.dst); },
1✔
277
            ebpf::MOD32_IMM  => { name = "mod32";  desc = alu_imm_str(name, &insn);  },
1✔
278
            ebpf::MOD32_REG  => { name = "mod32";  desc = alu_reg_str(name, &insn);  },
1✔
279
            ebpf::XOR32_IMM  => { name = "xor32";  desc = alu_imm_str(name, &insn);  },
1✔
280
            ebpf::XOR32_REG  => { name = "xor32";  desc = alu_reg_str(name, &insn);  },
1✔
281
            ebpf::MOV32_IMM  => { name = "mov32";  desc = alu_imm_str(name, &insn);  },
1✔
282
            ebpf::MOV32_REG  => { name = "mov32";  desc = alu_reg_str(name, &insn);  },
1✔
283
            ebpf::ARSH32_IMM => { name = "arsh32"; desc = alu_imm_str(name, &insn);  },
1✔
284
            ebpf::ARSH32_REG => { name = "arsh32"; desc = alu_reg_str(name, &insn);  },
1✔
285
            ebpf::LE         => { name = "le";     desc = byteswap_str(name, &insn); },
3✔
286
            ebpf::BE         => { name = "be";     desc = byteswap_str(name, &insn); },
4✔
287

288
            // BPF_ALU64 class
289
            ebpf::ADD64_IMM  => { name = "add64";  desc = alu_imm_str(name, &insn); },
4✔
290
            ebpf::ADD64_REG  => { name = "add64";  desc = alu_reg_str(name, &insn); },
2✔
291
            ebpf::SUB64_IMM  => { name = "sub64";  desc = alu_imm_str(name, &insn); },
1✔
292
            ebpf::SUB64_REG  => { name = "sub64";  desc = alu_reg_str(name, &insn); },
1✔
293
            ebpf::MUL64_IMM  => { name = "mul64";  desc = alu_imm_str(name, &insn); },
1✔
294
            ebpf::MUL64_REG  => { name = "mul64";  desc = alu_reg_str(name, &insn); },
1✔
295
            ebpf::DIV64_IMM  => { name = "div64";  desc = alu_imm_str(name, &insn); },
1✔
296
            ebpf::DIV64_REG  => { name = "div64";  desc = alu_reg_str(name, &insn); },
1✔
297
            ebpf::OR64_IMM   => { name = "or64";   desc = alu_imm_str(name, &insn); },
1✔
298
            ebpf::OR64_REG   => { name = "or64";   desc = alu_reg_str(name, &insn); },
1✔
299
            ebpf::AND64_IMM  => { name = "and64";  desc = alu_imm_str(name, &insn); },
1✔
300
            ebpf::AND64_REG  => { name = "and64";  desc = alu_reg_str(name, &insn); },
1✔
301
            ebpf::LSH64_IMM  => { name = "lsh64";  desc = alu_imm_str(name, &insn); },
1✔
302
            ebpf::LSH64_REG  => { name = "lsh64";  desc = alu_reg_str(name, &insn); },
1✔
303
            ebpf::RSH64_IMM  => { name = "rsh64";  desc = alu_imm_str(name, &insn); },
1✔
304
            ebpf::RSH64_REG  => { name = "rsh64";  desc = alu_reg_str(name, &insn); },
1✔
305
            ebpf::NEG64      => { name = "neg64";  desc = format!("{name} r{:}", insn.dst); },
2✔
306
            ebpf::MOD64_IMM  => { name = "mod64";  desc = alu_imm_str(name, &insn); },
1✔
307
            ebpf::MOD64_REG  => { name = "mod64";  desc = alu_reg_str(name, &insn); },
1✔
308
            ebpf::XOR64_IMM  => { name = "xor64";  desc = alu_imm_str(name, &insn); },
1✔
309
            ebpf::XOR64_REG  => { name = "xor64";  desc = alu_reg_str(name, &insn); },
1✔
310
            ebpf::MOV64_IMM  => { name = "mov64";  desc = alu_imm_str(name, &insn); },
1✔
311
            ebpf::MOV64_REG  => { name = "mov64";  desc = alu_reg_str(name, &insn); },
1✔
312
            ebpf::ARSH64_IMM => { name = "arsh64"; desc = alu_imm_str(name, &insn); },
1✔
313
            ebpf::ARSH64_REG => { name = "arsh64"; desc = alu_reg_str(name, &insn); },
1✔
314

315
            // BPF_JMP class
316
            ebpf::JA         => { name = "ja";   desc = if insn.off >= 0 { format!("{name} +{:#x}", insn.off) } else { format!("{name} -{:#x}", -insn.off) } },
1✔
317
            ebpf::JEQ_IMM    => { name = "jeq";  desc = jmp_imm_str(name, &insn); },
3✔
318
            ebpf::JEQ_REG    => { name = "jeq";  desc = jmp_reg_str(name, &insn); },
3✔
319
            ebpf::JGT_IMM    => { name = "jgt";  desc = jmp_imm_str(name, &insn); },
1✔
320
            ebpf::JGT_REG    => { name = "jgt";  desc = jmp_reg_str(name, &insn); },
1✔
321
            ebpf::JGE_IMM    => { name = "jge";  desc = jmp_imm_str(name, &insn); },
1✔
322
            ebpf::JGE_REG    => { name = "jge";  desc = jmp_reg_str(name, &insn); },
1✔
323
            ebpf::JLT_IMM    => { name = "jlt";  desc = jmp_imm_str(name, &insn); },
1✔
324
            ebpf::JLT_REG    => { name = "jlt";  desc = jmp_reg_str(name, &insn); },
1✔
325
            ebpf::JLE_IMM    => { name = "jle";  desc = jmp_imm_str(name, &insn); },
1✔
326
            ebpf::JLE_REG    => { name = "jle";  desc = jmp_reg_str(name, &insn); },
1✔
327
            ebpf::JSET_IMM   => { name = "jset"; desc = jmp_imm_str(name, &insn); },
1✔
328
            ebpf::JSET_REG   => { name = "jset"; desc = jmp_reg_str(name, &insn); },
1✔
329
            ebpf::JNE_IMM    => { name = "jne";  desc = jmp_imm_str(name, &insn); },
1✔
330
            ebpf::JNE_REG    => { name = "jne";  desc = jmp_reg_str(name, &insn); },
1✔
331
            ebpf::JSGT_IMM   => { name = "jsgt"; desc = jmp_imm_str(name, &insn); },
1✔
332
            ebpf::JSGT_REG   => { name = "jsgt"; desc = jmp_reg_str(name, &insn); },
1✔
333
            ebpf::JSGE_IMM   => { name = "jsge"; desc = jmp_imm_str(name, &insn); },
1✔
334
            ebpf::JSGE_REG   => { name = "jsge"; desc = jmp_reg_str(name, &insn); },
1✔
335
            ebpf::JSLT_IMM   => { name = "jslt"; desc = jmp_imm_str(name, &insn); },
1✔
336
            ebpf::JSLT_REG   => { name = "jslt"; desc = jmp_reg_str(name, &insn); },
1✔
337
            ebpf::JSLE_IMM   => { name = "jsle"; desc = jmp_imm_str(name, &insn); },
1✔
338
            ebpf::JSLE_REG   => { name = "jsle"; desc = jmp_reg_str(name, &insn); },
1✔
339
            ebpf::CALL       => {
340
                match insn.src {
1✔
341
                    0 => { name = "call"; desc = format!("{name} {:#x}", insn.imm); },
1✔
UNCOV
342
                    1 => { name = "callx"; desc = format!("{name} {:#x}", insn.imm); },
×
UNCOV
343
                    _ => { panic!("[Disassembler] Error: unsupported call insn (insn #{insn_ptr:?})"); }
×
344
                }
345
             },
UNCOV
346
            ebpf::TAIL_CALL  => { name = "tail_call"; desc = name.to_string(); },
×
347
            ebpf::EXIT       => { name = "exit";      desc = name.to_string(); },
1✔
348

349
            // BPF_JMP32 class
350
            ebpf::JEQ_IMM32  => { name = "jeq32";  desc = jmp_imm_str(name, &insn); },
2✔
351
            ebpf::JEQ_REG32  => { name = "jeq32";  desc = jmp_reg_str(name, &insn); },
2✔
352
            ebpf::JGT_IMM32  => { name = "jgt32";  desc = jmp_imm_str(name, &insn); },
1✔
353
            ebpf::JGT_REG32  => { name = "jgt32";  desc = jmp_reg_str(name, &insn); },
1✔
354
            ebpf::JGE_IMM32  => { name = "jge32";  desc = jmp_imm_str(name, &insn); },
1✔
355
            ebpf::JGE_REG32  => { name = "jge32";  desc = jmp_reg_str(name, &insn); },
1✔
356
            ebpf::JLT_IMM32  => { name = "jlt32";  desc = jmp_imm_str(name, &insn); },
1✔
357
            ebpf::JLT_REG32  => { name = "jlt32";  desc = jmp_reg_str(name, &insn); },
1✔
358
            ebpf::JLE_IMM32  => { name = "jle32";  desc = jmp_imm_str(name, &insn); },
1✔
359
            ebpf::JLE_REG32  => { name = "jle32";  desc = jmp_reg_str(name, &insn); },
1✔
360
            ebpf::JSET_IMM32 => { name = "jset32"; desc = jmp_imm_str(name, &insn); },
1✔
361
            ebpf::JSET_REG32 => { name = "jset32"; desc = jmp_reg_str(name, &insn); },
1✔
362
            ebpf::JNE_IMM32  => { name = "jne32";  desc = jmp_imm_str(name, &insn); },
1✔
363
            ebpf::JNE_REG32  => { name = "jne32";  desc = jmp_reg_str(name, &insn); },
1✔
364
            ebpf::JSGT_IMM32 => { name = "jsgt32"; desc = jmp_imm_str(name, &insn); },
1✔
365
            ebpf::JSGT_REG32 => { name = "jsgt32"; desc = jmp_reg_str(name, &insn); },
1✔
366
            ebpf::JSGE_IMM32 => { name = "jsge32"; desc = jmp_imm_str(name, &insn); },
1✔
367
            ebpf::JSGE_REG32 => { name = "jsge32"; desc = jmp_reg_str(name, &insn); },
1✔
368
            ebpf::JSLT_IMM32 => { name = "jslt32"; desc = jmp_imm_str(name, &insn); },
1✔
369
            ebpf::JSLT_REG32 => { name = "jslt32"; desc = jmp_reg_str(name, &insn); },
1✔
370
            ebpf::JSLE_IMM32 => { name = "jsle32"; desc = jmp_imm_str(name, &insn); },
1✔
371
            ebpf::JSLE_REG32 => { name = "jsle32"; desc = jmp_reg_str(name, &insn); },
1✔
372

373
            _                => {
UNCOV
374
                panic!("[Disassembler] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
×
375
                       insn.opc, insn_ptr);
376
            },
377
        };
378

379
        let hl_insn = HLInsn {
153✔
380
            opc: insn.opc,
153✔
381
            name: name.to_string(),
153✔
382
            desc,
153✔
383
            dst: insn.dst,
153✔
384
            src: insn.src,
153✔
385
            off: insn.off,
153✔
386
            imm,
153✔
387
        };
153✔
388

389
        res.push(hl_insn);
153✔
390

391
        insn_ptr += 1;
153✔
392
    }
393
    res
37✔
394
}
38✔
395

396
/// Disassemble an eBPF program into human-readable instructions and prints it to standard output.
397
///
398
/// The program is not checked for errors or inconsistencies.
399
///
400
/// # Examples
401
///
402
/// ```
403
/// use rbpf::disassembler;
404
/// let prog = &[
405
///     0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
406
///     0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
407
///     0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408
///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
409
///     0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
410
///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
411
/// ];
412
/// disassembler::disassemble(prog);
413
/// # // "\nadd64 r1, 0x605\nmov64 r2, 0x32\nmov64 r1, r0\nbe16 r0\nneg64 r2\nexit"
414
/// ```
415
///
416
/// This will produce the following output:
417
///
418
/// ```test
419
/// add64 r1, 0x605
420
/// mov64 r2, 0x32
421
/// mov64 r1, r0
422
/// be16 r0
423
/// neg64 r2
424
/// exit
425
/// ```
426
pub fn disassemble(prog: &[u8]) {
×
427
    #[cfg(feature = "std")]
428
    {
UNCOV
429
        for insn in to_insn_vec(prog) {
×
UNCOV
430
            println!("{}", insn.desc);
×
UNCOV
431
        }
×
432
    }
433
    #[cfg(not(feature = "std"))]
434
    {
435
        for insn in to_insn_vec(prog) {
436
            info!("{}", insn.desc);
437
        }
438
    }
UNCOV
439
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc