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

qmonnet / rbpf / 14939269399

09 May 2025 11:15PM UTC coverage: 94.957% (-0.3%) from 95.255%
14939269399

push

github

qmonnet
fix: Remove the 16-byte alignment requirement for the stack

Signed-off-by: Godones <chenlinfeng25@outlook.com>

4011 of 4224 relevant lines covered (94.96%)

254.71 hits per line

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

93.2
/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
use log::warn;
8
#[cfg(not(feature = "std"))]
9
use log::info;
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✔
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!("{name} [r{}-{:#x}], {:#x}", insn.dst, -(insn.off as isize), insn.imm)
4✔
39
    }
40
}
10✔
41

42
#[inline]
43
fn ld_reg_str(name: &str, insn: &ebpf::Insn) -> String {
10✔
44
    if insn.off >= 0 {
10✔
45
        format!("{name} r{}, [r{}+{:#x}]", insn.dst, insn.src, insn.off)
6✔
46
    } else {
47
        format!("{name} r{}, [r{}-{:#x}]", insn.dst, insn.src, -(insn.off as isize))
4✔
48
    }
49
}
10✔
50

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

60
#[inline]
61
fn ldabs_str(name: &str, insn: &ebpf::Insn) -> String {
5✔
62
    format!("{name} {:#x}", insn.imm)
5✔
63
}
5✔
64

65
#[inline]
66
fn ldind_str(name: &str, insn: &ebpf::Insn) -> String {
5✔
67
    format!("{name} r{}, {:#x}", insn.src, insn.imm)
5✔
68
}
5✔
69

70
#[inline]
71
fn jmp_imm_str(name: &str, insn: &ebpf::Insn) -> String {
25✔
72
    if insn.off >= 0 {
25✔
73
        format!("{name} r{}, {:#x}, +{:#x}", insn.dst, insn.imm, insn.off)
19✔
74
    } else {
75
        format!("{name} r{}, {:#x}, -{:#x}", insn.dst, insn.imm, -(insn.off as isize))
6✔
76
    }
77
}
25✔
78

79
#[inline]
80
fn jmp_reg_str(name: &str, insn: &ebpf::Insn) -> String {
25✔
81
    if insn.off >= 0 {
25✔
82
        format!("{name} r{}, r{}, +{:#x}", insn.dst, insn.src, insn.off)
19✔
83
    } else {
84
        format!("{name} r{}, r{}, -{:#x}", insn.dst, insn.src, -(insn.off as isize))
6✔
85
    }
86
}
25✔
87

88
/// High-level representation of an eBPF instruction.
89
///
90
/// In addition to standard operation code and various operand, this struct has the following
91
/// properties:
92
///
93
/// * It stores a name, corresponding to a mnemonic for the operation code.
94
/// * It also stores a description, which is a mnemonic for the full instruction, using the actual
95
///   values of the relevant operands, and that can be used for disassembling the eBPF program for
96
///   example.
97
/// * Immediate values are stored in an `i64` instead of a traditional i32, in order to merge the
98
///   two parts of (otherwise double-length) `LD_DW_IMM` instructions.
99
///
100
/// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
101
/// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
102
/// more concise version.
103
#[derive(Debug, PartialEq, Eq)]
104
pub struct HLInsn {
105
    /// Operation code.
106
    pub opc:  u8,
107
    /// Name (mnemonic). This name is not canon.
108
    pub name: String,
109
    /// Description of the instruction. This is not canon.
110
    pub desc: String,
111
    /// Destination register operand.
112
    pub dst:  u8,
113
    /// Source register operand.
114
    pub src:  u8,
115
    /// Offset operand.
116
    pub off:  i16,
117
    /// Immediate value operand. For `LD_DW_IMM` instructions, contains the whole value merged from
118
    /// the two 8-bytes parts of the instruction.
119
    pub imm:  i64,
120
}
121

122
/// Return a vector of `struct HLInsn` built from an eBPF program.
123
///
124
/// This is made public to provide a way to manipulate a program as a vector of instructions, in a
125
/// high-level format, for example for dumping the program instruction after instruction with a
126
/// custom format.
127
///
128
/// Note that the two parts of `LD_DW_IMM` instructions (that have the size of two standard
129
/// instructions) are considered as making a single immediate value. As a consequence, the number
130
/// of instructions stored in the vector may not be equal to the size in bytes of the program
131
/// divided by the length of an instructions.
132
///
133
/// To do so, the immediate value operand is stored as an `i64` instead as an i32, so be careful
134
/// when you use it (see example `examples/to_json.rs`).
135
///
136
/// This is to oppose to `ebpf::to_insn_vec()` function, that treats instructions on a low-level
137
/// ground and do not merge the parts of `LD_DW_IMM`. Also, the version in `ebpf` module does not
138
/// use names or descriptions when storing the instructions.
139
///
140
/// # Examples
141
///
142
/// ```
143
/// use rbpf::disassembler;
144
///
145
/// let prog = &[
146
///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
147
///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
148
///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
149
/// ];
150
///
151
/// let v = disassembler::to_insn_vec(prog);
152
/// assert_eq!(v, vec![
153
///     disassembler::HLInsn {
154
///         opc: 0x18,
155
///         name: "lddw".to_string(),
156
///         desc: "lddw r0, 0x1122334455667788".to_string(),
157
///         dst: 0,
158
///         src: 0,
159
///         off: 0,
160
///         imm: 0x1122334455667788
161
///     },
162
///     disassembler::HLInsn {
163
///         opc: 0x95,
164
///         name: "exit".to_string(),
165
///         desc: "exit".to_string(),
166
///         dst: 0,
167
///         src: 0,
168
///         off: 0,
169
///         imm: 0
170
///     },
171
/// ]);
172
/// ```
173
pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
38✔
174
    if prog.len() % ebpf::INSN_SIZE != 0 {
38✔
175
        panic!("[Disassembler] Error: eBPF program length must be a multiple of {:?} octets",
×
176
               ebpf::INSN_SIZE);
177
    }
38✔
178
    if prog.is_empty() {
38✔
179
        return vec![];
1✔
180
    }
37✔
181

182
    let mut res = vec![];
37✔
183
    let mut insn_ptr:usize = 0;
37✔
184

185
    while insn_ptr * ebpf::INSN_SIZE < prog.len() {
190✔
186
        let insn = ebpf::get_insn(prog, insn_ptr);
153✔
187

188
        let name;
189
        let desc;
190
        let mut imm = insn.imm as i64;
153✔
191
        match insn.opc {
153✔
192

193
            // BPF_LD class
194
            ebpf::LD_ABS_B   => { name = "ldabsb";  desc = ldabs_str(name, &insn); },
1✔
195
            ebpf::LD_ABS_H   => { name = "ldabsh";  desc = ldabs_str(name, &insn); },
1✔
196
            ebpf::LD_ABS_W   => { name = "ldabsw";  desc = ldabs_str(name, &insn); },
2✔
197
            ebpf::LD_ABS_DW  => { name = "ldabsdw"; desc = ldabs_str(name, &insn); },
1✔
198
            ebpf::LD_IND_B   => { name = "ldindb";  desc = ldind_str(name, &insn); },
1✔
199
            ebpf::LD_IND_H   => { name = "ldindh";  desc = ldind_str(name, &insn); },
1✔
200
            ebpf::LD_IND_W   => { name = "ldindw";  desc = ldind_str(name, &insn); },
2✔
201
            ebpf::LD_IND_DW  => { name = "ldinddw"; desc = ldind_str(name, &insn); },
1✔
202

203
            ebpf::LD_DW_IMM  => {
2✔
204
                insn_ptr += 1;
2✔
205
                let next_insn = ebpf::get_insn(prog, insn_ptr);
2✔
206
                imm = ((insn.imm as u32) as u64 + ((next_insn.imm as u64) << 32)) as i64;
2✔
207
                name = "lddw"; desc = format!("{name} r{:}, {imm:#x}", insn.dst);
2✔
208
            },
2✔
209

210
            // BPF_LDX class
211
            ebpf::LD_B_REG   => { name = "ldxb";  desc = ld_reg_str(name, &insn); },
2✔
212
            ebpf::LD_H_REG   => { name = "ldxh";  desc = ld_reg_str(name, &insn); },
2✔
213
            ebpf::LD_W_REG   => { name = "ldxw";  desc = ld_reg_str(name, &insn); },
3✔
214
            ebpf::LD_DW_REG  => { name = "ldxdw"; desc = ld_reg_str(name, &insn); },
3✔
215

216
            // BPF_ST class
217
            ebpf::ST_B_IMM   => { name = "stb";  desc = ld_st_imm_str(name, &insn); },
2✔
218
            ebpf::ST_H_IMM   => { name = "sth";  desc = ld_st_imm_str(name, &insn); },
3✔
219
            ebpf::ST_W_IMM   => { name = "stw";  desc = ld_st_imm_str(name, &insn); },
3✔
220
            ebpf::ST_DW_IMM  => { name = "stdw"; desc = ld_st_imm_str(name, &insn); },
2✔
221

222
            // BPF_STX class
223
            ebpf::ST_B_REG   => { name = "stxb";      desc = st_reg_str(name, &insn); },
1✔
224
            ebpf::ST_H_REG   => { name = "stxh";      desc = st_reg_str(name, &insn); },
2✔
225
            ebpf::ST_W_REG   => { name = "stxw";      desc = st_reg_str(name, &insn); },
2✔
226
            ebpf::ST_DW_REG  => { name = "stxdw";     desc = st_reg_str(name, &insn); },
1✔
227
            ebpf::ST_W_XADD  => { name = "stxxaddw";  desc = st_reg_str(name, &insn); },
×
228
            ebpf::ST_DW_XADD => { name = "stxxadddw"; desc = st_reg_str(name, &insn); },
×
229

230
            // BPF_ALU class
231
            ebpf::ADD32_IMM  => { name = "add32";  desc = alu_imm_str(name, &insn);  },
1✔
232
            ebpf::ADD32_REG  => { name = "add32";  desc = alu_reg_str(name, &insn);  },
1✔
233
            ebpf::SUB32_IMM  => { name = "sub32";  desc = alu_imm_str(name, &insn);  },
1✔
234
            ebpf::SUB32_REG  => { name = "sub32";  desc = alu_reg_str(name, &insn);  },
1✔
235
            ebpf::MUL32_IMM  => { name = "mul32";  desc = alu_imm_str(name, &insn);  },
1✔
236
            ebpf::MUL32_REG  => { name = "mul32";  desc = alu_reg_str(name, &insn);  },
1✔
237
            ebpf::DIV32_IMM  => { name = "div32";  desc = alu_imm_str(name, &insn);  },
1✔
238
            ebpf::DIV32_REG  => { name = "div32";  desc = alu_reg_str(name, &insn);  },
1✔
239
            ebpf::OR32_IMM   => { name = "or32";   desc = alu_imm_str(name, &insn);  },
1✔
240
            ebpf::OR32_REG   => { name = "or32";   desc = alu_reg_str(name, &insn);  },
1✔
241
            ebpf::AND32_IMM  => { name = "and32";  desc = alu_imm_str(name, &insn);  },
1✔
242
            ebpf::AND32_REG  => { name = "and32";  desc = alu_reg_str(name, &insn);  },
1✔
243
            ebpf::LSH32_IMM  => { name = "lsh32";  desc = alu_imm_str(name, &insn);  },
1✔
244
            ebpf::LSH32_REG  => { name = "lsh32";  desc = alu_reg_str(name, &insn);  },
1✔
245
            ebpf::RSH32_IMM  => { name = "rsh32";  desc = alu_imm_str(name, &insn);  },
1✔
246
            ebpf::RSH32_REG  => { name = "rsh32";  desc = alu_reg_str(name, &insn);  },
1✔
247
            ebpf::NEG32      => { name = "neg32";  desc = format!("{name} r{:}", insn.dst); },
1✔
248
            ebpf::MOD32_IMM  => { name = "mod32";  desc = alu_imm_str(name, &insn);  },
1✔
249
            ebpf::MOD32_REG  => { name = "mod32";  desc = alu_reg_str(name, &insn);  },
1✔
250
            ebpf::XOR32_IMM  => { name = "xor32";  desc = alu_imm_str(name, &insn);  },
1✔
251
            ebpf::XOR32_REG  => { name = "xor32";  desc = alu_reg_str(name, &insn);  },
1✔
252
            ebpf::MOV32_IMM  => { name = "mov32";  desc = alu_imm_str(name, &insn);  },
1✔
253
            ebpf::MOV32_REG  => { name = "mov32";  desc = alu_reg_str(name, &insn);  },
1✔
254
            ebpf::ARSH32_IMM => { name = "arsh32"; desc = alu_imm_str(name, &insn);  },
1✔
255
            ebpf::ARSH32_REG => { name = "arsh32"; desc = alu_reg_str(name, &insn);  },
1✔
256
            ebpf::LE         => { name = "le";     desc = byteswap_str(name, &insn); },
3✔
257
            ebpf::BE         => { name = "be";     desc = byteswap_str(name, &insn); },
4✔
258

259
            // BPF_ALU64 class
260
            ebpf::ADD64_IMM  => { name = "add64";  desc = alu_imm_str(name, &insn); },
4✔
261
            ebpf::ADD64_REG  => { name = "add64";  desc = alu_reg_str(name, &insn); },
2✔
262
            ebpf::SUB64_IMM  => { name = "sub64";  desc = alu_imm_str(name, &insn); },
1✔
263
            ebpf::SUB64_REG  => { name = "sub64";  desc = alu_reg_str(name, &insn); },
1✔
264
            ebpf::MUL64_IMM  => { name = "mul64";  desc = alu_imm_str(name, &insn); },
1✔
265
            ebpf::MUL64_REG  => { name = "mul64";  desc = alu_reg_str(name, &insn); },
1✔
266
            ebpf::DIV64_IMM  => { name = "div64";  desc = alu_imm_str(name, &insn); },
1✔
267
            ebpf::DIV64_REG  => { name = "div64";  desc = alu_reg_str(name, &insn); },
1✔
268
            ebpf::OR64_IMM   => { name = "or64";   desc = alu_imm_str(name, &insn); },
1✔
269
            ebpf::OR64_REG   => { name = "or64";   desc = alu_reg_str(name, &insn); },
1✔
270
            ebpf::AND64_IMM  => { name = "and64";  desc = alu_imm_str(name, &insn); },
1✔
271
            ebpf::AND64_REG  => { name = "and64";  desc = alu_reg_str(name, &insn); },
1✔
272
            ebpf::LSH64_IMM  => { name = "lsh64";  desc = alu_imm_str(name, &insn); },
1✔
273
            ebpf::LSH64_REG  => { name = "lsh64";  desc = alu_reg_str(name, &insn); },
1✔
274
            ebpf::RSH64_IMM  => { name = "rsh64";  desc = alu_imm_str(name, &insn); },
1✔
275
            ebpf::RSH64_REG  => { name = "rsh64";  desc = alu_reg_str(name, &insn); },
1✔
276
            ebpf::NEG64      => { name = "neg64";  desc = format!("{name} r{:}", insn.dst); },
2✔
277
            ebpf::MOD64_IMM  => { name = "mod64";  desc = alu_imm_str(name, &insn); },
1✔
278
            ebpf::MOD64_REG  => { name = "mod64";  desc = alu_reg_str(name, &insn); },
1✔
279
            ebpf::XOR64_IMM  => { name = "xor64";  desc = alu_imm_str(name, &insn); },
1✔
280
            ebpf::XOR64_REG  => { name = "xor64";  desc = alu_reg_str(name, &insn); },
1✔
281
            ebpf::MOV64_IMM  => { name = "mov64";  desc = alu_imm_str(name, &insn); },
1✔
282
            ebpf::MOV64_REG  => { name = "mov64";  desc = alu_reg_str(name, &insn); },
1✔
283
            ebpf::ARSH64_IMM => { name = "arsh64"; desc = alu_imm_str(name, &insn); },
1✔
284
            ebpf::ARSH64_REG => { name = "arsh64"; desc = alu_reg_str(name, &insn); },
1✔
285

286
            // BPF_JMP class
287
            ebpf::JA         => { name = "ja";   desc = if insn.off >= 0 { format!("{name} +{:#x}", insn.off) } else { format!("{name} -{:#x}", -insn.off) } },
1✔
288
            ebpf::JEQ_IMM    => { name = "jeq";  desc = jmp_imm_str(name, &insn); },
3✔
289
            ebpf::JEQ_REG    => { name = "jeq";  desc = jmp_reg_str(name, &insn); },
3✔
290
            ebpf::JGT_IMM    => { name = "jgt";  desc = jmp_imm_str(name, &insn); },
1✔
291
            ebpf::JGT_REG    => { name = "jgt";  desc = jmp_reg_str(name, &insn); },
1✔
292
            ebpf::JGE_IMM    => { name = "jge";  desc = jmp_imm_str(name, &insn); },
1✔
293
            ebpf::JGE_REG    => { name = "jge";  desc = jmp_reg_str(name, &insn); },
1✔
294
            ebpf::JLT_IMM    => { name = "jlt";  desc = jmp_imm_str(name, &insn); },
1✔
295
            ebpf::JLT_REG    => { name = "jlt";  desc = jmp_reg_str(name, &insn); },
1✔
296
            ebpf::JLE_IMM    => { name = "jle";  desc = jmp_imm_str(name, &insn); },
1✔
297
            ebpf::JLE_REG    => { name = "jle";  desc = jmp_reg_str(name, &insn); },
1✔
298
            ebpf::JSET_IMM   => { name = "jset"; desc = jmp_imm_str(name, &insn); },
1✔
299
            ebpf::JSET_REG   => { name = "jset"; desc = jmp_reg_str(name, &insn); },
1✔
300
            ebpf::JNE_IMM    => { name = "jne";  desc = jmp_imm_str(name, &insn); },
1✔
301
            ebpf::JNE_REG    => { name = "jne";  desc = jmp_reg_str(name, &insn); },
1✔
302
            ebpf::JSGT_IMM   => { name = "jsgt"; desc = jmp_imm_str(name, &insn); },
1✔
303
            ebpf::JSGT_REG   => { name = "jsgt"; desc = jmp_reg_str(name, &insn); },
1✔
304
            ebpf::JSGE_IMM   => { name = "jsge"; desc = jmp_imm_str(name, &insn); },
1✔
305
            ebpf::JSGE_REG   => { name = "jsge"; desc = jmp_reg_str(name, &insn); },
1✔
306
            ebpf::JSLT_IMM   => { name = "jslt"; desc = jmp_imm_str(name, &insn); },
1✔
307
            ebpf::JSLT_REG   => { name = "jslt"; desc = jmp_reg_str(name, &insn); },
1✔
308
            ebpf::JSLE_IMM   => { name = "jsle"; desc = jmp_imm_str(name, &insn); },
1✔
309
            ebpf::JSLE_REG   => { name = "jsle"; desc = jmp_reg_str(name, &insn); },
1✔
310
            ebpf::CALL       => {
311
                match insn.src {
1✔
312
                    0 => { name = "call"; desc = format!("{name} {:#x}", insn.imm); },
1✔
313
                    1 => { name = "callx"; desc = format!("{name} {:#x}", insn.imm); },
×
314
                    _ => { panic!("[Disassembler] Error: unsupported call insn (insn #{:?})", insn_ptr); }
×
315
                }
316
             },
317
            ebpf::TAIL_CALL  => { name = "tail_call"; desc = name.to_string(); },
×
318
            ebpf::EXIT       => { name = "exit";      desc = name.to_string(); },
1✔
319

320
            // BPF_JMP32 class
321
            ebpf::JEQ_IMM32  => { name = "jeq32";  desc = jmp_imm_str(name, &insn); },
2✔
322
            ebpf::JEQ_REG32  => { name = "jeq32";  desc = jmp_reg_str(name, &insn); },
2✔
323
            ebpf::JGT_IMM32  => { name = "jgt32";  desc = jmp_imm_str(name, &insn); },
1✔
324
            ebpf::JGT_REG32  => { name = "jgt32";  desc = jmp_reg_str(name, &insn); },
1✔
325
            ebpf::JGE_IMM32  => { name = "jge32";  desc = jmp_imm_str(name, &insn); },
1✔
326
            ebpf::JGE_REG32  => { name = "jge32";  desc = jmp_reg_str(name, &insn); },
1✔
327
            ebpf::JLT_IMM32  => { name = "jlt32";  desc = jmp_imm_str(name, &insn); },
1✔
328
            ebpf::JLT_REG32  => { name = "jlt32";  desc = jmp_reg_str(name, &insn); },
1✔
329
            ebpf::JLE_IMM32  => { name = "jle32";  desc = jmp_imm_str(name, &insn); },
1✔
330
            ebpf::JLE_REG32  => { name = "jle32";  desc = jmp_reg_str(name, &insn); },
1✔
331
            ebpf::JSET_IMM32 => { name = "jset32"; desc = jmp_imm_str(name, &insn); },
1✔
332
            ebpf::JSET_REG32 => { name = "jset32"; desc = jmp_reg_str(name, &insn); },
1✔
333
            ebpf::JNE_IMM32  => { name = "jne32";  desc = jmp_imm_str(name, &insn); },
1✔
334
            ebpf::JNE_REG32  => { name = "jne32";  desc = jmp_reg_str(name, &insn); },
1✔
335
            ebpf::JSGT_IMM32 => { name = "jsgt32"; desc = jmp_imm_str(name, &insn); },
1✔
336
            ebpf::JSGT_REG32 => { name = "jsgt32"; desc = jmp_reg_str(name, &insn); },
1✔
337
            ebpf::JSGE_IMM32 => { name = "jsge32"; desc = jmp_imm_str(name, &insn); },
1✔
338
            ebpf::JSGE_REG32 => { name = "jsge32"; desc = jmp_reg_str(name, &insn); },
1✔
339
            ebpf::JSLT_IMM32 => { name = "jslt32"; desc = jmp_imm_str(name, &insn); },
1✔
340
            ebpf::JSLT_REG32 => { name = "jslt32"; desc = jmp_reg_str(name, &insn); },
1✔
341
            ebpf::JSLE_IMM32 => { name = "jsle32"; desc = jmp_imm_str(name, &insn); },
1✔
342
            ebpf::JSLE_REG32 => { name = "jsle32"; desc = jmp_reg_str(name, &insn); },
1✔
343

344
            _                => {
345
                panic!("[Disassembler] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
×
346
                       insn.opc, insn_ptr);
347
            },
348
        };
349

350
        let hl_insn = HLInsn {
153✔
351
            opc:  insn.opc,
153✔
352
            name: name.to_string(),
153✔
353
            desc,
153✔
354
            dst:  insn.dst,
153✔
355
            src:  insn.src,
153✔
356
            off:  insn.off,
153✔
357
            imm,
153✔
358
        };
153✔
359

360
        res.push(hl_insn);
153✔
361

362
        insn_ptr += 1;
153✔
363
    };
364
    res
37✔
365
}
38✔
366

367
/// Disassemble an eBPF program into human-readable instructions and prints it to standard output.
368
///
369
/// The program is not checked for errors or inconsistencies.
370
///
371
/// # Examples
372
///
373
/// ```
374
/// use rbpf::disassembler;
375
/// let prog = &[
376
///     0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
377
///     0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
378
///     0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
379
///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
380
///     0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381
///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
382
/// ];
383
/// disassembler::disassemble(prog);
384
/// # // "\nadd64 r1, 0x605\nmov64 r2, 0x32\nmov64 r1, r0\nbe16 r0\nneg64 r2\nexit"
385
/// ```
386
///
387
/// This will produce the following output:
388
///
389
/// ```test
390
/// add64 r1, 0x605
391
/// mov64 r2, 0x32
392
/// mov64 r1, r0
393
/// be16 r0
394
/// neg64 r2
395
/// exit
396
/// ```
397
pub fn disassemble(prog: &[u8]) {
×
398
    #[cfg(feature = "std")] {
399
        for insn in to_insn_vec(prog) {
×
400
            println!("{}", insn.desc);
×
401
        }
×
402
    }
403
    #[cfg(not(feature = "std"))] {
404
        for insn in to_insn_vec(prog) {
405
            info!("{}", insn.desc);
406
        }
407
    }
408
}
×
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