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