xref: /DragonOS/kernel/crates/rbpf/src/disassembler.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1*fae6e9adSlinfeng // SPDX-License-Identifier: (Apache-2.0 OR MIT)
2*fae6e9adSlinfeng // Copyright 2017 6WIND S.A. <quentin.monnet@6wind.com>
3*fae6e9adSlinfeng 
4*fae6e9adSlinfeng //! Functions in this module are used to handle eBPF programs with a higher level representation,
5*fae6e9adSlinfeng //! for example to disassemble the code into a human-readable format.
6*fae6e9adSlinfeng 
7*fae6e9adSlinfeng use alloc::{
8*fae6e9adSlinfeng     format,
9*fae6e9adSlinfeng     string::{String, ToString},
10*fae6e9adSlinfeng     vec,
11*fae6e9adSlinfeng     vec::Vec,
12*fae6e9adSlinfeng };
13*fae6e9adSlinfeng 
14*fae6e9adSlinfeng use log::warn;
15*fae6e9adSlinfeng 
16*fae6e9adSlinfeng use crate::ebpf;
17*fae6e9adSlinfeng 
18*fae6e9adSlinfeng #[inline]
alu_imm_str(name: &str, insn: &ebpf::Insn) -> String19*fae6e9adSlinfeng fn alu_imm_str(name: &str, insn: &ebpf::Insn) -> String {
20*fae6e9adSlinfeng     format!("{name} r{}, {:#x}", insn.dst, insn.imm)
21*fae6e9adSlinfeng }
22*fae6e9adSlinfeng 
23*fae6e9adSlinfeng #[inline]
alu_reg_str(name: &str, insn: &ebpf::Insn) -> String24*fae6e9adSlinfeng fn alu_reg_str(name: &str, insn: &ebpf::Insn) -> String {
25*fae6e9adSlinfeng     format!("{name} r{}, r{}", insn.dst, insn.src)
26*fae6e9adSlinfeng }
27*fae6e9adSlinfeng 
28*fae6e9adSlinfeng #[inline]
byteswap_str(name: &str, insn: &ebpf::Insn) -> String29*fae6e9adSlinfeng fn byteswap_str(name: &str, insn: &ebpf::Insn) -> String {
30*fae6e9adSlinfeng     match insn.imm {
31*fae6e9adSlinfeng         16 | 32 | 64 => {}
32*fae6e9adSlinfeng         _ => warn!("[Disassembler] Warning: Invalid offset value for {name} insn"),
33*fae6e9adSlinfeng     }
34*fae6e9adSlinfeng     format!("{name}{} r{}", insn.imm, insn.dst)
35*fae6e9adSlinfeng }
36*fae6e9adSlinfeng 
37*fae6e9adSlinfeng #[inline]
ld_st_imm_str(name: &str, insn: &ebpf::Insn) -> String38*fae6e9adSlinfeng fn ld_st_imm_str(name: &str, insn: &ebpf::Insn) -> String {
39*fae6e9adSlinfeng     if insn.off >= 0 {
40*fae6e9adSlinfeng         format!("{name} [r{}+{:#x}], {:#x}", insn.dst, insn.off, insn.imm)
41*fae6e9adSlinfeng     } else {
42*fae6e9adSlinfeng         format!(
43*fae6e9adSlinfeng             "{name} [r{}-{:#x}], {:#x}",
44*fae6e9adSlinfeng             insn.dst,
45*fae6e9adSlinfeng             -(insn.off as isize),
46*fae6e9adSlinfeng             insn.imm
47*fae6e9adSlinfeng         )
48*fae6e9adSlinfeng     }
49*fae6e9adSlinfeng }
50*fae6e9adSlinfeng 
51*fae6e9adSlinfeng #[inline]
ld_reg_str(name: &str, insn: &ebpf::Insn) -> String52*fae6e9adSlinfeng fn ld_reg_str(name: &str, insn: &ebpf::Insn) -> String {
53*fae6e9adSlinfeng     if insn.off >= 0 {
54*fae6e9adSlinfeng         format!("{name} r{}, [r{}+{:#x}]", insn.dst, insn.src, insn.off)
55*fae6e9adSlinfeng     } else {
56*fae6e9adSlinfeng         format!(
57*fae6e9adSlinfeng             "{name} r{}, [r{}-{:#x}]",
58*fae6e9adSlinfeng             insn.dst,
59*fae6e9adSlinfeng             insn.src,
60*fae6e9adSlinfeng             -(insn.off as isize)
61*fae6e9adSlinfeng         )
62*fae6e9adSlinfeng     }
63*fae6e9adSlinfeng }
64*fae6e9adSlinfeng 
65*fae6e9adSlinfeng #[inline]
st_reg_str(name: &str, insn: &ebpf::Insn) -> String66*fae6e9adSlinfeng fn st_reg_str(name: &str, insn: &ebpf::Insn) -> String {
67*fae6e9adSlinfeng     if insn.off >= 0 {
68*fae6e9adSlinfeng         format!("{name} [r{}+{:#x}], r{}", insn.dst, insn.off, insn.src)
69*fae6e9adSlinfeng     } else {
70*fae6e9adSlinfeng         format!(
71*fae6e9adSlinfeng             "{name} [r{}-{:#x}], r{}",
72*fae6e9adSlinfeng             insn.dst,
73*fae6e9adSlinfeng             -(insn.off as isize),
74*fae6e9adSlinfeng             insn.src
75*fae6e9adSlinfeng         )
76*fae6e9adSlinfeng     }
77*fae6e9adSlinfeng }
78*fae6e9adSlinfeng 
79*fae6e9adSlinfeng #[inline]
ldabs_str(name: &str, insn: &ebpf::Insn) -> String80*fae6e9adSlinfeng fn ldabs_str(name: &str, insn: &ebpf::Insn) -> String {
81*fae6e9adSlinfeng     format!("{name} {:#x}", insn.imm)
82*fae6e9adSlinfeng }
83*fae6e9adSlinfeng 
84*fae6e9adSlinfeng #[inline]
ldind_str(name: &str, insn: &ebpf::Insn) -> String85*fae6e9adSlinfeng fn ldind_str(name: &str, insn: &ebpf::Insn) -> String {
86*fae6e9adSlinfeng     format!("{name} r{}, {:#x}", insn.src, insn.imm)
87*fae6e9adSlinfeng }
88*fae6e9adSlinfeng 
89*fae6e9adSlinfeng #[inline]
jmp_imm_str(name: &str, insn: &ebpf::Insn) -> String90*fae6e9adSlinfeng fn jmp_imm_str(name: &str, insn: &ebpf::Insn) -> String {
91*fae6e9adSlinfeng     if insn.off >= 0 {
92*fae6e9adSlinfeng         format!("{name} r{}, {:#x}, +{:#x}", insn.dst, insn.imm, insn.off)
93*fae6e9adSlinfeng     } else {
94*fae6e9adSlinfeng         format!(
95*fae6e9adSlinfeng             "{name} r{}, {:#x}, -{:#x}",
96*fae6e9adSlinfeng             insn.dst,
97*fae6e9adSlinfeng             insn.imm,
98*fae6e9adSlinfeng             -(insn.off as isize)
99*fae6e9adSlinfeng         )
100*fae6e9adSlinfeng     }
101*fae6e9adSlinfeng }
102*fae6e9adSlinfeng 
103*fae6e9adSlinfeng #[inline]
jmp_reg_str(name: &str, insn: &ebpf::Insn) -> String104*fae6e9adSlinfeng fn jmp_reg_str(name: &str, insn: &ebpf::Insn) -> String {
105*fae6e9adSlinfeng     if insn.off >= 0 {
106*fae6e9adSlinfeng         format!("{name} r{}, r{}, +{:#x}", insn.dst, insn.src, insn.off)
107*fae6e9adSlinfeng     } else {
108*fae6e9adSlinfeng         format!(
109*fae6e9adSlinfeng             "{name} r{}, r{}, -{:#x}",
110*fae6e9adSlinfeng             insn.dst,
111*fae6e9adSlinfeng             insn.src,
112*fae6e9adSlinfeng             -(insn.off as isize)
113*fae6e9adSlinfeng         )
114*fae6e9adSlinfeng     }
115*fae6e9adSlinfeng }
116*fae6e9adSlinfeng 
117*fae6e9adSlinfeng /// High-level representation of an eBPF instruction.
118*fae6e9adSlinfeng ///
119*fae6e9adSlinfeng /// In addition to standard operation code and various operand, this struct has the following
120*fae6e9adSlinfeng /// properties:
121*fae6e9adSlinfeng ///
122*fae6e9adSlinfeng /// * It stores a name, corresponding to a mnemonic for the operation code.
123*fae6e9adSlinfeng /// * It also stores a description, which is a mnemonic for the full instruction, using the actual
124*fae6e9adSlinfeng ///   values of the relevant operands, and that can be used for disassembling the eBPF program for
125*fae6e9adSlinfeng ///   example.
126*fae6e9adSlinfeng /// * Immediate values are stored in an `i64` instead of a traditional i32, in order to merge the
127*fae6e9adSlinfeng ///   two parts of (otherwise double-length) `LD_DW_IMM` instructions.
128*fae6e9adSlinfeng ///
129*fae6e9adSlinfeng /// See <https://www.kernel.org/doc/Documentation/networking/filter.txt> for the Linux kernel
130*fae6e9adSlinfeng /// documentation about eBPF, or <https://github.com/iovisor/bpf-docs/blob/master/eBPF.md> for a
131*fae6e9adSlinfeng /// more concise version.
132*fae6e9adSlinfeng #[derive(Debug, PartialEq, Eq)]
133*fae6e9adSlinfeng pub struct HLInsn {
134*fae6e9adSlinfeng     /// Operation code.
135*fae6e9adSlinfeng     pub opc: u8,
136*fae6e9adSlinfeng     /// Name (mnemonic). This name is not canon.
137*fae6e9adSlinfeng     pub name: String,
138*fae6e9adSlinfeng     /// Description of the instruction. This is not canon.
139*fae6e9adSlinfeng     pub desc: String,
140*fae6e9adSlinfeng     /// Destination register operand.
141*fae6e9adSlinfeng     pub dst: u8,
142*fae6e9adSlinfeng     /// Source register operand.
143*fae6e9adSlinfeng     pub src: u8,
144*fae6e9adSlinfeng     /// Offset operand.
145*fae6e9adSlinfeng     pub off: i16,
146*fae6e9adSlinfeng     /// Immediate value operand. For `LD_DW_IMM` instructions, contains the whole value merged from
147*fae6e9adSlinfeng     /// the two 8-bytes parts of the instruction.
148*fae6e9adSlinfeng     pub imm: i64,
149*fae6e9adSlinfeng }
150*fae6e9adSlinfeng 
151*fae6e9adSlinfeng /// Return a vector of `struct HLInsn` built from an eBPF program.
152*fae6e9adSlinfeng ///
153*fae6e9adSlinfeng /// This is made public to provide a way to manipulate a program as a vector of instructions, in a
154*fae6e9adSlinfeng /// high-level format, for example for dumping the program instruction after instruction with a
155*fae6e9adSlinfeng /// custom format.
156*fae6e9adSlinfeng ///
157*fae6e9adSlinfeng /// Note that the two parts of `LD_DW_IMM` instructions (that have the size of two standard
158*fae6e9adSlinfeng /// instructions) are considered as making a single immediate value. As a consequence, the number
159*fae6e9adSlinfeng /// of instructions stored in the vector may not be equal to the size in bytes of the program
160*fae6e9adSlinfeng /// divided by the length of an instructions.
161*fae6e9adSlinfeng ///
162*fae6e9adSlinfeng /// To do so, the immediate value operand is stored as an `i64` instead as an i32, so be careful
163*fae6e9adSlinfeng /// when you use it (see example `examples/to_json.rs`).
164*fae6e9adSlinfeng ///
165*fae6e9adSlinfeng /// This is to oppose to `ebpf::to_insn_vec()` function, that treats instructions on a low-level
166*fae6e9adSlinfeng /// ground and do not merge the parts of `LD_DW_IMM`. Also, the version in `ebpf` module does not
167*fae6e9adSlinfeng /// use names or descriptions when storing the instructions.
168*fae6e9adSlinfeng ///
169*fae6e9adSlinfeng /// # Examples
170*fae6e9adSlinfeng ///
171*fae6e9adSlinfeng /// ```
172*fae6e9adSlinfeng /// use rbpf::disassembler;
173*fae6e9adSlinfeng ///
174*fae6e9adSlinfeng /// let prog = &[
175*fae6e9adSlinfeng ///     0x18, 0x00, 0x00, 0x00, 0x88, 0x77, 0x66, 0x55,
176*fae6e9adSlinfeng ///     0x00, 0x00, 0x00, 0x00, 0x44, 0x33, 0x22, 0x11,
177*fae6e9adSlinfeng ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
178*fae6e9adSlinfeng /// ];
179*fae6e9adSlinfeng ///
180*fae6e9adSlinfeng /// let v = disassembler::to_insn_vec(prog);
181*fae6e9adSlinfeng /// assert_eq!(v, vec![
182*fae6e9adSlinfeng ///     disassembler::HLInsn {
183*fae6e9adSlinfeng ///         opc: 0x18,
184*fae6e9adSlinfeng ///         name: "lddw".to_string(),
185*fae6e9adSlinfeng ///         desc: "lddw r0, 0x1122334455667788".to_string(),
186*fae6e9adSlinfeng ///         dst: 0,
187*fae6e9adSlinfeng ///         src: 0,
188*fae6e9adSlinfeng ///         off: 0,
189*fae6e9adSlinfeng ///         imm: 0x1122334455667788
190*fae6e9adSlinfeng ///     },
191*fae6e9adSlinfeng ///     disassembler::HLInsn {
192*fae6e9adSlinfeng ///         opc: 0x95,
193*fae6e9adSlinfeng ///         name: "exit".to_string(),
194*fae6e9adSlinfeng ///         desc: "exit".to_string(),
195*fae6e9adSlinfeng ///         dst: 0,
196*fae6e9adSlinfeng ///         src: 0,
197*fae6e9adSlinfeng ///         off: 0,
198*fae6e9adSlinfeng ///         imm: 0
199*fae6e9adSlinfeng ///     },
200*fae6e9adSlinfeng /// ]);
201*fae6e9adSlinfeng /// ```
to_insn_vec(prog: &[u8]) -> Vec<HLInsn>202*fae6e9adSlinfeng pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
203*fae6e9adSlinfeng     if prog.len() % ebpf::INSN_SIZE != 0 {
204*fae6e9adSlinfeng         panic!(
205*fae6e9adSlinfeng             "[Disassembler] Error: eBPF program length must be a multiple of {:?} octets",
206*fae6e9adSlinfeng             ebpf::INSN_SIZE
207*fae6e9adSlinfeng         );
208*fae6e9adSlinfeng     }
209*fae6e9adSlinfeng     if prog.is_empty() {
210*fae6e9adSlinfeng         return vec![];
211*fae6e9adSlinfeng     }
212*fae6e9adSlinfeng 
213*fae6e9adSlinfeng     let mut res = vec![];
214*fae6e9adSlinfeng     let mut insn_ptr: usize = 0;
215*fae6e9adSlinfeng 
216*fae6e9adSlinfeng     while insn_ptr * ebpf::INSN_SIZE < prog.len() {
217*fae6e9adSlinfeng         let insn = ebpf::get_insn(prog, insn_ptr);
218*fae6e9adSlinfeng 
219*fae6e9adSlinfeng         let name;
220*fae6e9adSlinfeng         let desc;
221*fae6e9adSlinfeng         let mut imm = insn.imm as i64;
222*fae6e9adSlinfeng         match insn.opc {
223*fae6e9adSlinfeng             // BPF_LD class
224*fae6e9adSlinfeng             ebpf::LD_ABS_B => {
225*fae6e9adSlinfeng                 name = "ldabsb";
226*fae6e9adSlinfeng                 desc = ldabs_str(name, &insn);
227*fae6e9adSlinfeng             }
228*fae6e9adSlinfeng             ebpf::LD_ABS_H => {
229*fae6e9adSlinfeng                 name = "ldabsh";
230*fae6e9adSlinfeng                 desc = ldabs_str(name, &insn);
231*fae6e9adSlinfeng             }
232*fae6e9adSlinfeng             ebpf::LD_ABS_W => {
233*fae6e9adSlinfeng                 name = "ldabsw";
234*fae6e9adSlinfeng                 desc = ldabs_str(name, &insn);
235*fae6e9adSlinfeng             }
236*fae6e9adSlinfeng             ebpf::LD_ABS_DW => {
237*fae6e9adSlinfeng                 name = "ldabsdw";
238*fae6e9adSlinfeng                 desc = ldabs_str(name, &insn);
239*fae6e9adSlinfeng             }
240*fae6e9adSlinfeng             ebpf::LD_IND_B => {
241*fae6e9adSlinfeng                 name = "ldindb";
242*fae6e9adSlinfeng                 desc = ldind_str(name, &insn);
243*fae6e9adSlinfeng             }
244*fae6e9adSlinfeng             ebpf::LD_IND_H => {
245*fae6e9adSlinfeng                 name = "ldindh";
246*fae6e9adSlinfeng                 desc = ldind_str(name, &insn);
247*fae6e9adSlinfeng             }
248*fae6e9adSlinfeng             ebpf::LD_IND_W => {
249*fae6e9adSlinfeng                 name = "ldindw";
250*fae6e9adSlinfeng                 desc = ldind_str(name, &insn);
251*fae6e9adSlinfeng             }
252*fae6e9adSlinfeng             ebpf::LD_IND_DW => {
253*fae6e9adSlinfeng                 name = "ldinddw";
254*fae6e9adSlinfeng                 desc = ldind_str(name, &insn);
255*fae6e9adSlinfeng             }
256*fae6e9adSlinfeng 
257*fae6e9adSlinfeng             ebpf::LD_DW_IMM => {
258*fae6e9adSlinfeng                 insn_ptr += 1;
259*fae6e9adSlinfeng                 let next_insn = ebpf::get_insn(prog, insn_ptr);
260*fae6e9adSlinfeng                 imm = ((insn.imm as u32) as u64 + ((next_insn.imm as u64) << 32)) as i64;
261*fae6e9adSlinfeng                 name = "lddw";
262*fae6e9adSlinfeng                 desc = format!("{name} r{:}, {imm:#x}", insn.dst);
263*fae6e9adSlinfeng             }
264*fae6e9adSlinfeng 
265*fae6e9adSlinfeng             // BPF_LDX class
266*fae6e9adSlinfeng             ebpf::LD_B_REG => {
267*fae6e9adSlinfeng                 name = "ldxb";
268*fae6e9adSlinfeng                 desc = ld_reg_str(name, &insn);
269*fae6e9adSlinfeng             }
270*fae6e9adSlinfeng             ebpf::LD_H_REG => {
271*fae6e9adSlinfeng                 name = "ldxh";
272*fae6e9adSlinfeng                 desc = ld_reg_str(name, &insn);
273*fae6e9adSlinfeng             }
274*fae6e9adSlinfeng             ebpf::LD_W_REG => {
275*fae6e9adSlinfeng                 name = "ldxw";
276*fae6e9adSlinfeng                 desc = ld_reg_str(name, &insn);
277*fae6e9adSlinfeng             }
278*fae6e9adSlinfeng             ebpf::LD_DW_REG => {
279*fae6e9adSlinfeng                 name = "ldxdw";
280*fae6e9adSlinfeng                 desc = ld_reg_str(name, &insn);
281*fae6e9adSlinfeng             }
282*fae6e9adSlinfeng 
283*fae6e9adSlinfeng             // BPF_ST class
284*fae6e9adSlinfeng             ebpf::ST_B_IMM => {
285*fae6e9adSlinfeng                 name = "stb";
286*fae6e9adSlinfeng                 desc = ld_st_imm_str(name, &insn);
287*fae6e9adSlinfeng             }
288*fae6e9adSlinfeng             ebpf::ST_H_IMM => {
289*fae6e9adSlinfeng                 name = "sth";
290*fae6e9adSlinfeng                 desc = ld_st_imm_str(name, &insn);
291*fae6e9adSlinfeng             }
292*fae6e9adSlinfeng             ebpf::ST_W_IMM => {
293*fae6e9adSlinfeng                 name = "stw";
294*fae6e9adSlinfeng                 desc = ld_st_imm_str(name, &insn);
295*fae6e9adSlinfeng             }
296*fae6e9adSlinfeng             ebpf::ST_DW_IMM => {
297*fae6e9adSlinfeng                 name = "stdw";
298*fae6e9adSlinfeng                 desc = ld_st_imm_str(name, &insn);
299*fae6e9adSlinfeng             }
300*fae6e9adSlinfeng 
301*fae6e9adSlinfeng             // BPF_STX class
302*fae6e9adSlinfeng             ebpf::ST_B_REG => {
303*fae6e9adSlinfeng                 name = "stxb";
304*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
305*fae6e9adSlinfeng             }
306*fae6e9adSlinfeng             ebpf::ST_H_REG => {
307*fae6e9adSlinfeng                 name = "stxh";
308*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
309*fae6e9adSlinfeng             }
310*fae6e9adSlinfeng             ebpf::ST_W_REG => {
311*fae6e9adSlinfeng                 name = "stxw";
312*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
313*fae6e9adSlinfeng             }
314*fae6e9adSlinfeng             ebpf::ST_DW_REG => {
315*fae6e9adSlinfeng                 name = "stxdw";
316*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
317*fae6e9adSlinfeng             }
318*fae6e9adSlinfeng             ebpf::ST_W_XADD => {
319*fae6e9adSlinfeng                 name = "stxxaddw";
320*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
321*fae6e9adSlinfeng             }
322*fae6e9adSlinfeng             ebpf::ST_DW_XADD => {
323*fae6e9adSlinfeng                 name = "stxxadddw";
324*fae6e9adSlinfeng                 desc = st_reg_str(name, &insn);
325*fae6e9adSlinfeng             }
326*fae6e9adSlinfeng 
327*fae6e9adSlinfeng             // BPF_ALU class
328*fae6e9adSlinfeng             ebpf::ADD32_IMM => {
329*fae6e9adSlinfeng                 name = "add32";
330*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
331*fae6e9adSlinfeng             }
332*fae6e9adSlinfeng             ebpf::ADD32_REG => {
333*fae6e9adSlinfeng                 name = "add32";
334*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
335*fae6e9adSlinfeng             }
336*fae6e9adSlinfeng             ebpf::SUB32_IMM => {
337*fae6e9adSlinfeng                 name = "sub32";
338*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
339*fae6e9adSlinfeng             }
340*fae6e9adSlinfeng             ebpf::SUB32_REG => {
341*fae6e9adSlinfeng                 name = "sub32";
342*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
343*fae6e9adSlinfeng             }
344*fae6e9adSlinfeng             ebpf::MUL32_IMM => {
345*fae6e9adSlinfeng                 name = "mul32";
346*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
347*fae6e9adSlinfeng             }
348*fae6e9adSlinfeng             ebpf::MUL32_REG => {
349*fae6e9adSlinfeng                 name = "mul32";
350*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
351*fae6e9adSlinfeng             }
352*fae6e9adSlinfeng             ebpf::DIV32_IMM => {
353*fae6e9adSlinfeng                 name = "div32";
354*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
355*fae6e9adSlinfeng             }
356*fae6e9adSlinfeng             ebpf::DIV32_REG => {
357*fae6e9adSlinfeng                 name = "div32";
358*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
359*fae6e9adSlinfeng             }
360*fae6e9adSlinfeng             ebpf::OR32_IMM => {
361*fae6e9adSlinfeng                 name = "or32";
362*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
363*fae6e9adSlinfeng             }
364*fae6e9adSlinfeng             ebpf::OR32_REG => {
365*fae6e9adSlinfeng                 name = "or32";
366*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
367*fae6e9adSlinfeng             }
368*fae6e9adSlinfeng             ebpf::AND32_IMM => {
369*fae6e9adSlinfeng                 name = "and32";
370*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
371*fae6e9adSlinfeng             }
372*fae6e9adSlinfeng             ebpf::AND32_REG => {
373*fae6e9adSlinfeng                 name = "and32";
374*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
375*fae6e9adSlinfeng             }
376*fae6e9adSlinfeng             ebpf::LSH32_IMM => {
377*fae6e9adSlinfeng                 name = "lsh32";
378*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
379*fae6e9adSlinfeng             }
380*fae6e9adSlinfeng             ebpf::LSH32_REG => {
381*fae6e9adSlinfeng                 name = "lsh32";
382*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
383*fae6e9adSlinfeng             }
384*fae6e9adSlinfeng             ebpf::RSH32_IMM => {
385*fae6e9adSlinfeng                 name = "rsh32";
386*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
387*fae6e9adSlinfeng             }
388*fae6e9adSlinfeng             ebpf::RSH32_REG => {
389*fae6e9adSlinfeng                 name = "rsh32";
390*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
391*fae6e9adSlinfeng             }
392*fae6e9adSlinfeng             ebpf::NEG32 => {
393*fae6e9adSlinfeng                 name = "neg32";
394*fae6e9adSlinfeng                 desc = format!("{name} r{:}", insn.dst);
395*fae6e9adSlinfeng             }
396*fae6e9adSlinfeng             ebpf::MOD32_IMM => {
397*fae6e9adSlinfeng                 name = "mod32";
398*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
399*fae6e9adSlinfeng             }
400*fae6e9adSlinfeng             ebpf::MOD32_REG => {
401*fae6e9adSlinfeng                 name = "mod32";
402*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
403*fae6e9adSlinfeng             }
404*fae6e9adSlinfeng             ebpf::XOR32_IMM => {
405*fae6e9adSlinfeng                 name = "xor32";
406*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
407*fae6e9adSlinfeng             }
408*fae6e9adSlinfeng             ebpf::XOR32_REG => {
409*fae6e9adSlinfeng                 name = "xor32";
410*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
411*fae6e9adSlinfeng             }
412*fae6e9adSlinfeng             ebpf::MOV32_IMM => {
413*fae6e9adSlinfeng                 name = "mov32";
414*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
415*fae6e9adSlinfeng             }
416*fae6e9adSlinfeng             ebpf::MOV32_REG => {
417*fae6e9adSlinfeng                 name = "mov32";
418*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
419*fae6e9adSlinfeng             }
420*fae6e9adSlinfeng             ebpf::ARSH32_IMM => {
421*fae6e9adSlinfeng                 name = "arsh32";
422*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
423*fae6e9adSlinfeng             }
424*fae6e9adSlinfeng             ebpf::ARSH32_REG => {
425*fae6e9adSlinfeng                 name = "arsh32";
426*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
427*fae6e9adSlinfeng             }
428*fae6e9adSlinfeng             ebpf::LE => {
429*fae6e9adSlinfeng                 name = "le";
430*fae6e9adSlinfeng                 desc = byteswap_str(name, &insn);
431*fae6e9adSlinfeng             }
432*fae6e9adSlinfeng             ebpf::BE => {
433*fae6e9adSlinfeng                 name = "be";
434*fae6e9adSlinfeng                 desc = byteswap_str(name, &insn);
435*fae6e9adSlinfeng             }
436*fae6e9adSlinfeng 
437*fae6e9adSlinfeng             // BPF_ALU64 class
438*fae6e9adSlinfeng             ebpf::ADD64_IMM => {
439*fae6e9adSlinfeng                 name = "add64";
440*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
441*fae6e9adSlinfeng             }
442*fae6e9adSlinfeng             ebpf::ADD64_REG => {
443*fae6e9adSlinfeng                 name = "add64";
444*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
445*fae6e9adSlinfeng             }
446*fae6e9adSlinfeng             ebpf::SUB64_IMM => {
447*fae6e9adSlinfeng                 name = "sub64";
448*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
449*fae6e9adSlinfeng             }
450*fae6e9adSlinfeng             ebpf::SUB64_REG => {
451*fae6e9adSlinfeng                 name = "sub64";
452*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
453*fae6e9adSlinfeng             }
454*fae6e9adSlinfeng             ebpf::MUL64_IMM => {
455*fae6e9adSlinfeng                 name = "mul64";
456*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
457*fae6e9adSlinfeng             }
458*fae6e9adSlinfeng             ebpf::MUL64_REG => {
459*fae6e9adSlinfeng                 name = "mul64";
460*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
461*fae6e9adSlinfeng             }
462*fae6e9adSlinfeng             ebpf::DIV64_IMM => {
463*fae6e9adSlinfeng                 name = "div64";
464*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
465*fae6e9adSlinfeng             }
466*fae6e9adSlinfeng             ebpf::DIV64_REG => {
467*fae6e9adSlinfeng                 name = "div64";
468*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
469*fae6e9adSlinfeng             }
470*fae6e9adSlinfeng             ebpf::OR64_IMM => {
471*fae6e9adSlinfeng                 name = "or64";
472*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
473*fae6e9adSlinfeng             }
474*fae6e9adSlinfeng             ebpf::OR64_REG => {
475*fae6e9adSlinfeng                 name = "or64";
476*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
477*fae6e9adSlinfeng             }
478*fae6e9adSlinfeng             ebpf::AND64_IMM => {
479*fae6e9adSlinfeng                 name = "and64";
480*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
481*fae6e9adSlinfeng             }
482*fae6e9adSlinfeng             ebpf::AND64_REG => {
483*fae6e9adSlinfeng                 name = "and64";
484*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
485*fae6e9adSlinfeng             }
486*fae6e9adSlinfeng             ebpf::LSH64_IMM => {
487*fae6e9adSlinfeng                 name = "lsh64";
488*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
489*fae6e9adSlinfeng             }
490*fae6e9adSlinfeng             ebpf::LSH64_REG => {
491*fae6e9adSlinfeng                 name = "lsh64";
492*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
493*fae6e9adSlinfeng             }
494*fae6e9adSlinfeng             ebpf::RSH64_IMM => {
495*fae6e9adSlinfeng                 name = "rsh64";
496*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
497*fae6e9adSlinfeng             }
498*fae6e9adSlinfeng             ebpf::RSH64_REG => {
499*fae6e9adSlinfeng                 name = "rsh64";
500*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
501*fae6e9adSlinfeng             }
502*fae6e9adSlinfeng             ebpf::NEG64 => {
503*fae6e9adSlinfeng                 name = "neg64";
504*fae6e9adSlinfeng                 desc = format!("{name} r{:}", insn.dst);
505*fae6e9adSlinfeng             }
506*fae6e9adSlinfeng             ebpf::MOD64_IMM => {
507*fae6e9adSlinfeng                 name = "mod64";
508*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
509*fae6e9adSlinfeng             }
510*fae6e9adSlinfeng             ebpf::MOD64_REG => {
511*fae6e9adSlinfeng                 name = "mod64";
512*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
513*fae6e9adSlinfeng             }
514*fae6e9adSlinfeng             ebpf::XOR64_IMM => {
515*fae6e9adSlinfeng                 name = "xor64";
516*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
517*fae6e9adSlinfeng             }
518*fae6e9adSlinfeng             ebpf::XOR64_REG => {
519*fae6e9adSlinfeng                 name = "xor64";
520*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
521*fae6e9adSlinfeng             }
522*fae6e9adSlinfeng             ebpf::MOV64_IMM => {
523*fae6e9adSlinfeng                 name = "mov64";
524*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
525*fae6e9adSlinfeng             }
526*fae6e9adSlinfeng             ebpf::MOV64_REG => {
527*fae6e9adSlinfeng                 name = "mov64";
528*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
529*fae6e9adSlinfeng             }
530*fae6e9adSlinfeng             ebpf::ARSH64_IMM => {
531*fae6e9adSlinfeng                 name = "arsh64";
532*fae6e9adSlinfeng                 desc = alu_imm_str(name, &insn);
533*fae6e9adSlinfeng             }
534*fae6e9adSlinfeng             ebpf::ARSH64_REG => {
535*fae6e9adSlinfeng                 name = "arsh64";
536*fae6e9adSlinfeng                 desc = alu_reg_str(name, &insn);
537*fae6e9adSlinfeng             }
538*fae6e9adSlinfeng 
539*fae6e9adSlinfeng             // BPF_JMP class
540*fae6e9adSlinfeng             ebpf::JA => {
541*fae6e9adSlinfeng                 name = "ja";
542*fae6e9adSlinfeng                 desc = if insn.off >= 0 {
543*fae6e9adSlinfeng                     format!("{name} +{:#x}", insn.off)
544*fae6e9adSlinfeng                 } else {
545*fae6e9adSlinfeng                     format!("{name} -{:#x}", -insn.off)
546*fae6e9adSlinfeng                 }
547*fae6e9adSlinfeng             }
548*fae6e9adSlinfeng             ebpf::JEQ_IMM => {
549*fae6e9adSlinfeng                 name = "jeq";
550*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
551*fae6e9adSlinfeng             }
552*fae6e9adSlinfeng             ebpf::JEQ_REG => {
553*fae6e9adSlinfeng                 name = "jeq";
554*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
555*fae6e9adSlinfeng             }
556*fae6e9adSlinfeng             ebpf::JGT_IMM => {
557*fae6e9adSlinfeng                 name = "jgt";
558*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
559*fae6e9adSlinfeng             }
560*fae6e9adSlinfeng             ebpf::JGT_REG => {
561*fae6e9adSlinfeng                 name = "jgt";
562*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
563*fae6e9adSlinfeng             }
564*fae6e9adSlinfeng             ebpf::JGE_IMM => {
565*fae6e9adSlinfeng                 name = "jge";
566*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
567*fae6e9adSlinfeng             }
568*fae6e9adSlinfeng             ebpf::JGE_REG => {
569*fae6e9adSlinfeng                 name = "jge";
570*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
571*fae6e9adSlinfeng             }
572*fae6e9adSlinfeng             ebpf::JLT_IMM => {
573*fae6e9adSlinfeng                 name = "jlt";
574*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
575*fae6e9adSlinfeng             }
576*fae6e9adSlinfeng             ebpf::JLT_REG => {
577*fae6e9adSlinfeng                 name = "jlt";
578*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
579*fae6e9adSlinfeng             }
580*fae6e9adSlinfeng             ebpf::JLE_IMM => {
581*fae6e9adSlinfeng                 name = "jle";
582*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
583*fae6e9adSlinfeng             }
584*fae6e9adSlinfeng             ebpf::JLE_REG => {
585*fae6e9adSlinfeng                 name = "jle";
586*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
587*fae6e9adSlinfeng             }
588*fae6e9adSlinfeng             ebpf::JSET_IMM => {
589*fae6e9adSlinfeng                 name = "jset";
590*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
591*fae6e9adSlinfeng             }
592*fae6e9adSlinfeng             ebpf::JSET_REG => {
593*fae6e9adSlinfeng                 name = "jset";
594*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
595*fae6e9adSlinfeng             }
596*fae6e9adSlinfeng             ebpf::JNE_IMM => {
597*fae6e9adSlinfeng                 name = "jne";
598*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
599*fae6e9adSlinfeng             }
600*fae6e9adSlinfeng             ebpf::JNE_REG => {
601*fae6e9adSlinfeng                 name = "jne";
602*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
603*fae6e9adSlinfeng             }
604*fae6e9adSlinfeng             ebpf::JSGT_IMM => {
605*fae6e9adSlinfeng                 name = "jsgt";
606*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
607*fae6e9adSlinfeng             }
608*fae6e9adSlinfeng             ebpf::JSGT_REG => {
609*fae6e9adSlinfeng                 name = "jsgt";
610*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
611*fae6e9adSlinfeng             }
612*fae6e9adSlinfeng             ebpf::JSGE_IMM => {
613*fae6e9adSlinfeng                 name = "jsge";
614*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
615*fae6e9adSlinfeng             }
616*fae6e9adSlinfeng             ebpf::JSGE_REG => {
617*fae6e9adSlinfeng                 name = "jsge";
618*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
619*fae6e9adSlinfeng             }
620*fae6e9adSlinfeng             ebpf::JSLT_IMM => {
621*fae6e9adSlinfeng                 name = "jslt";
622*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
623*fae6e9adSlinfeng             }
624*fae6e9adSlinfeng             ebpf::JSLT_REG => {
625*fae6e9adSlinfeng                 name = "jslt";
626*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
627*fae6e9adSlinfeng             }
628*fae6e9adSlinfeng             ebpf::JSLE_IMM => {
629*fae6e9adSlinfeng                 name = "jsle";
630*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
631*fae6e9adSlinfeng             }
632*fae6e9adSlinfeng             ebpf::JSLE_REG => {
633*fae6e9adSlinfeng                 name = "jsle";
634*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
635*fae6e9adSlinfeng             }
636*fae6e9adSlinfeng             ebpf::CALL => {
637*fae6e9adSlinfeng                 name = "call";
638*fae6e9adSlinfeng                 desc = format!("{name} {:#x}", insn.imm);
639*fae6e9adSlinfeng             }
640*fae6e9adSlinfeng             ebpf::TAIL_CALL => {
641*fae6e9adSlinfeng                 name = "tail_call";
642*fae6e9adSlinfeng                 desc = name.to_string();
643*fae6e9adSlinfeng             }
644*fae6e9adSlinfeng             ebpf::EXIT => {
645*fae6e9adSlinfeng                 name = "exit";
646*fae6e9adSlinfeng                 desc = name.to_string();
647*fae6e9adSlinfeng             }
648*fae6e9adSlinfeng 
649*fae6e9adSlinfeng             // BPF_JMP32 class
650*fae6e9adSlinfeng             ebpf::JEQ_IMM32 => {
651*fae6e9adSlinfeng                 name = "jeq32";
652*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
653*fae6e9adSlinfeng             }
654*fae6e9adSlinfeng             ebpf::JEQ_REG32 => {
655*fae6e9adSlinfeng                 name = "jeq32";
656*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
657*fae6e9adSlinfeng             }
658*fae6e9adSlinfeng             ebpf::JGT_IMM32 => {
659*fae6e9adSlinfeng                 name = "jgt32";
660*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
661*fae6e9adSlinfeng             }
662*fae6e9adSlinfeng             ebpf::JGT_REG32 => {
663*fae6e9adSlinfeng                 name = "jgt32";
664*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
665*fae6e9adSlinfeng             }
666*fae6e9adSlinfeng             ebpf::JGE_IMM32 => {
667*fae6e9adSlinfeng                 name = "jge32";
668*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
669*fae6e9adSlinfeng             }
670*fae6e9adSlinfeng             ebpf::JGE_REG32 => {
671*fae6e9adSlinfeng                 name = "jge32";
672*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
673*fae6e9adSlinfeng             }
674*fae6e9adSlinfeng             ebpf::JLT_IMM32 => {
675*fae6e9adSlinfeng                 name = "jlt32";
676*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
677*fae6e9adSlinfeng             }
678*fae6e9adSlinfeng             ebpf::JLT_REG32 => {
679*fae6e9adSlinfeng                 name = "jlt32";
680*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
681*fae6e9adSlinfeng             }
682*fae6e9adSlinfeng             ebpf::JLE_IMM32 => {
683*fae6e9adSlinfeng                 name = "jle32";
684*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
685*fae6e9adSlinfeng             }
686*fae6e9adSlinfeng             ebpf::JLE_REG32 => {
687*fae6e9adSlinfeng                 name = "jle32";
688*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
689*fae6e9adSlinfeng             }
690*fae6e9adSlinfeng             ebpf::JSET_IMM32 => {
691*fae6e9adSlinfeng                 name = "jset32";
692*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
693*fae6e9adSlinfeng             }
694*fae6e9adSlinfeng             ebpf::JSET_REG32 => {
695*fae6e9adSlinfeng                 name = "jset32";
696*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
697*fae6e9adSlinfeng             }
698*fae6e9adSlinfeng             ebpf::JNE_IMM32 => {
699*fae6e9adSlinfeng                 name = "jne32";
700*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
701*fae6e9adSlinfeng             }
702*fae6e9adSlinfeng             ebpf::JNE_REG32 => {
703*fae6e9adSlinfeng                 name = "jne32";
704*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
705*fae6e9adSlinfeng             }
706*fae6e9adSlinfeng             ebpf::JSGT_IMM32 => {
707*fae6e9adSlinfeng                 name = "jsgt32";
708*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
709*fae6e9adSlinfeng             }
710*fae6e9adSlinfeng             ebpf::JSGT_REG32 => {
711*fae6e9adSlinfeng                 name = "jsgt32";
712*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
713*fae6e9adSlinfeng             }
714*fae6e9adSlinfeng             ebpf::JSGE_IMM32 => {
715*fae6e9adSlinfeng                 name = "jsge32";
716*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
717*fae6e9adSlinfeng             }
718*fae6e9adSlinfeng             ebpf::JSGE_REG32 => {
719*fae6e9adSlinfeng                 name = "jsge32";
720*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
721*fae6e9adSlinfeng             }
722*fae6e9adSlinfeng             ebpf::JSLT_IMM32 => {
723*fae6e9adSlinfeng                 name = "jslt32";
724*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
725*fae6e9adSlinfeng             }
726*fae6e9adSlinfeng             ebpf::JSLT_REG32 => {
727*fae6e9adSlinfeng                 name = "jslt32";
728*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
729*fae6e9adSlinfeng             }
730*fae6e9adSlinfeng             ebpf::JSLE_IMM32 => {
731*fae6e9adSlinfeng                 name = "jsle32";
732*fae6e9adSlinfeng                 desc = jmp_imm_str(name, &insn);
733*fae6e9adSlinfeng             }
734*fae6e9adSlinfeng             ebpf::JSLE_REG32 => {
735*fae6e9adSlinfeng                 name = "jsle32";
736*fae6e9adSlinfeng                 desc = jmp_reg_str(name, &insn);
737*fae6e9adSlinfeng             }
738*fae6e9adSlinfeng 
739*fae6e9adSlinfeng             _ => {
740*fae6e9adSlinfeng                 panic!(
741*fae6e9adSlinfeng                     "[Disassembler] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
742*fae6e9adSlinfeng                     insn.opc, insn_ptr
743*fae6e9adSlinfeng                 );
744*fae6e9adSlinfeng             }
745*fae6e9adSlinfeng         };
746*fae6e9adSlinfeng 
747*fae6e9adSlinfeng         let hl_insn = HLInsn {
748*fae6e9adSlinfeng             opc: insn.opc,
749*fae6e9adSlinfeng             name: name.to_string(),
750*fae6e9adSlinfeng             desc,
751*fae6e9adSlinfeng             dst: insn.dst,
752*fae6e9adSlinfeng             src: insn.src,
753*fae6e9adSlinfeng             off: insn.off,
754*fae6e9adSlinfeng             imm,
755*fae6e9adSlinfeng         };
756*fae6e9adSlinfeng 
757*fae6e9adSlinfeng         res.push(hl_insn);
758*fae6e9adSlinfeng 
759*fae6e9adSlinfeng         insn_ptr += 1;
760*fae6e9adSlinfeng     }
761*fae6e9adSlinfeng     res
762*fae6e9adSlinfeng }
763*fae6e9adSlinfeng 
764*fae6e9adSlinfeng /// Disassemble an eBPF program into human-readable instructions and prints it to standard output.
765*fae6e9adSlinfeng ///
766*fae6e9adSlinfeng /// The program is not checked for errors or inconsistencies.
767*fae6e9adSlinfeng ///
768*fae6e9adSlinfeng /// # Examples
769*fae6e9adSlinfeng ///
770*fae6e9adSlinfeng /// ```
771*fae6e9adSlinfeng /// use rbpf::disassembler;
772*fae6e9adSlinfeng /// let prog = &[
773*fae6e9adSlinfeng ///     0x07, 0x01, 0x00, 0x00, 0x05, 0x06, 0x00, 0x00,
774*fae6e9adSlinfeng ///     0xb7, 0x02, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00,
775*fae6e9adSlinfeng ///     0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776*fae6e9adSlinfeng ///     0xdc, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
777*fae6e9adSlinfeng ///     0x87, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778*fae6e9adSlinfeng ///     0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
779*fae6e9adSlinfeng /// ];
780*fae6e9adSlinfeng /// disassembler::disassemble(prog);
781*fae6e9adSlinfeng /// # // "\nadd64 r1, 0x605\nmov64 r2, 0x32\nmov64 r1, r0\nbe16 r0\nneg64 r2\nexit"
782*fae6e9adSlinfeng /// ```
783*fae6e9adSlinfeng ///
784*fae6e9adSlinfeng /// This will produce the following output:
785*fae6e9adSlinfeng ///
786*fae6e9adSlinfeng /// ```test
787*fae6e9adSlinfeng /// add64 r1, 0x605
788*fae6e9adSlinfeng /// mov64 r2, 0x32
789*fae6e9adSlinfeng /// mov64 r1, r0
790*fae6e9adSlinfeng /// be16 r0
791*fae6e9adSlinfeng /// neg64 r2
792*fae6e9adSlinfeng /// exit
793*fae6e9adSlinfeng /// ```
disassemble(prog: &[u8])794*fae6e9adSlinfeng pub fn disassemble(prog: &[u8]) {
795*fae6e9adSlinfeng     #[cfg(feature = "std")]
796*fae6e9adSlinfeng     {
797*fae6e9adSlinfeng         for insn in to_insn_vec(prog) {
798*fae6e9adSlinfeng             println!("{}", insn.desc);
799*fae6e9adSlinfeng         }
800*fae6e9adSlinfeng     }
801*fae6e9adSlinfeng     #[cfg(not(feature = "std"))]
802*fae6e9adSlinfeng     {
803*fae6e9adSlinfeng         for insn in to_insn_vec(prog) {
804*fae6e9adSlinfeng             log::info!("{}", insn.desc);
805*fae6e9adSlinfeng         }
806*fae6e9adSlinfeng     }
807*fae6e9adSlinfeng }
808