فهرست منبع

Merge pull request #15 from badboy/correct-disasm

disasm: fix disassembler and add related tests
Quentin Monnet 8 سال پیش
والد
کامیت
43f2a1aff4
2فایلهای تغییر یافته به همراه295 افزوده شده و 13 حذف شده
  1. 18 13
      src/disassembler.rs
  2. 277 0
      tests/disassembler.rs

+ 18 - 13
src/disassembler.rs

@@ -22,11 +22,11 @@ fn alu_reg_str(name: &str, insn: &ebpf::Insn) -> String {
 
 #[inline]
 fn byteswap_str(name: &str, insn: &ebpf::Insn) -> String {
-    match insn.off {
+    match insn.imm {
         16 | 32 | 64 => {},
         _ => println!("[Disassembler] Warning: Invalid offset value for {} insn", name)
     }
-    format!("{}{} r{}", name, insn.off, insn.dst)
+    format!("{}{} r{}", name, insn.imm, insn.dst)
 }
 
 #[inline]
@@ -35,7 +35,12 @@ fn ld_st_imm_str(name: &str, insn: &ebpf::Insn) -> String {
 }
 
 #[inline]
-fn ld_st_reg_str(name: &str, insn: &ebpf::Insn) -> String {
+fn ld_reg_str(name: &str, insn: &ebpf::Insn) -> String {
+    format!("{} r{}, [r{}+{:#x}]", name, insn.dst, insn.src, insn.off)
+}
+
+#[inline]
+fn st_reg_str(name: &str, insn: &ebpf::Insn) -> String {
     format!("{} [r{}+{:#x}], r{}", name, insn.dst, insn.off, insn.src)
 }
 
@@ -182,10 +187,10 @@ pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
             },
 
             // BPF_LDX class
-            ebpf::LD_B_REG   => { name = "ldxb";  desc = ld_st_reg_str(name, &insn); },
-            ebpf::LD_H_REG   => { name = "ldxh";  desc = ld_st_reg_str(name, &insn); },
-            ebpf::LD_W_REG   => { name = "ldxw";  desc = ld_st_reg_str(name, &insn); },
-            ebpf::LD_DW_REG  => { name = "ldxdw"; desc = ld_st_reg_str(name, &insn); },
+            ebpf::LD_B_REG   => { name = "ldxb";  desc = ld_reg_str(name, &insn); },
+            ebpf::LD_H_REG   => { name = "ldxh";  desc = ld_reg_str(name, &insn); },
+            ebpf::LD_W_REG   => { name = "ldxw";  desc = ld_reg_str(name, &insn); },
+            ebpf::LD_DW_REG  => { name = "ldxdw"; desc = ld_reg_str(name, &insn); },
 
             // BPF_ST class
             ebpf::ST_B_IMM   => { name = "stb";  desc = ld_st_imm_str(name, &insn); },
@@ -194,12 +199,12 @@ pub fn to_insn_vec(prog: &[u8]) -> Vec<HLInsn> {
             ebpf::ST_DW_IMM  => { name = "stdw"; desc = ld_st_imm_str(name, &insn); },
 
             // BPF_STX class
-            ebpf::ST_B_REG   => { name = "stxb";      desc = ld_st_reg_str(name, &insn); },
-            ebpf::ST_H_REG   => { name = "stxh";      desc = ld_st_reg_str(name, &insn); },
-            ebpf::ST_W_REG   => { name = "stxw";      desc = ld_st_reg_str(name, &insn); },
-            ebpf::ST_DW_REG  => { name = "stxdw";     desc = ld_st_reg_str(name, &insn); },
-            ebpf::ST_W_XADD  => { name = "stxxaddw";  desc = ld_st_reg_str(name, &insn); },
-            ebpf::ST_DW_XADD => { name = "stxxadddw"; desc = ld_st_reg_str(name, &insn); },
+            ebpf::ST_B_REG   => { name = "stxb";      desc = st_reg_str(name, &insn); },
+            ebpf::ST_H_REG   => { name = "stxh";      desc = st_reg_str(name, &insn); },
+            ebpf::ST_W_REG   => { name = "stxw";      desc = st_reg_str(name, &insn); },
+            ebpf::ST_DW_REG  => { name = "stxdw";     desc = st_reg_str(name, &insn); },
+            ebpf::ST_W_XADD  => { name = "stxxaddw";  desc = st_reg_str(name, &insn); },
+            ebpf::ST_DW_XADD => { name = "stxxadddw"; desc = st_reg_str(name, &insn); },
 
             // BPF_ALU class
             ebpf::ADD32_IMM  => { name = "add32";  desc = alu_imm_str(name, &insn);  },

+ 277 - 0
tests/disassembler.rs

@@ -0,0 +1,277 @@
+// Copyright 2017 Jan-Erik Rediger <badboy@archlinux.us>
+//
+// Adopted from tests in `tests/assembler.rs`
+//
+// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
+// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
+// copied, modified, or distributed except according to those terms.
+
+
+extern crate rbpf;
+mod common;
+
+use rbpf::assembler::assemble;
+use rbpf::disassembler::to_insn_vec;
+
+// Using a macro to keep actual line numbers in failure output
+macro_rules! disasm {
+    ($src:expr) => {
+        {
+            let src = $src;
+            let asm = assemble(src).expect("Can't assemble from string");
+            let insn = to_insn_vec(&asm);
+            let reasm = insn.into_iter().map(|ins| ins.desc).collect::<Vec<_>>().join("\n");
+
+            assert_eq!(src, reasm);
+        }
+    }
+}
+
+#[test]
+fn test_empty() {
+    disasm!("");
+}
+
+// Example for InstructionType::NoOperand.
+#[test]
+fn test_exit() {
+    disasm!("exit");
+}
+
+// Example for InstructionType::AluBinary.
+#[test]
+fn test_add64() {
+    disasm!("add64 r1, r3");
+    disasm!("add64 r1, 0x5");
+}
+
+// Example for InstructionType::AluUnary.
+#[test]
+fn test_neg64() {
+    disasm!("neg64 r1");
+}
+
+// Example for InstructionType::LoadReg.
+#[test]
+fn test_ldxw() {
+    disasm!("ldxw r1, [r2+0x5]");
+}
+
+// Example for InstructionType::StoreImm.
+#[test]
+fn test_stw() {
+    disasm!("stw [r2+0x5], 0x7");
+}
+
+// Example for InstructionType::StoreReg.
+#[test]
+fn test_stxw() {
+    disasm!("stxw [r2+0x5], r8");
+}
+
+// Example for InstructionType::JumpUnconditional.
+#[test]
+fn test_ja() {
+    disasm!("ja +0x8");
+}
+
+// Example for InstructionType::JumpConditional.
+#[test]
+fn test_jeq() {
+    disasm!("jeq r1, 0x4, +0x8");
+    disasm!("jeq r1, r3, +0x8");
+}
+
+// Example for InstructionType::Call.
+#[test]
+fn test_call() {
+    disasm!("call 0x3");
+}
+
+// Example for InstructionType::Endian.
+#[test]
+fn test_be32() {
+    disasm!("be32 r1");
+}
+
+// Example for InstructionType::LoadImm.
+#[test]
+fn test_lddw() {
+    disasm!("lddw r1, 0x1234abcd5678eeff");
+    disasm!("lddw r1, 0xff11ee22dd33cc44");
+}
+
+// Example for InstructionType::LoadAbs.
+#[test]
+fn test_ldabsw() {
+    disasm!("ldabsw 0x1");
+}
+
+// Example for InstructionType::LoadInd.
+#[test]
+fn test_ldindw() {
+    disasm!("ldindw r1, 0x2");
+}
+
+// Example for InstructionType::LoadReg.
+#[test]
+fn test_ldxdw() {
+    disasm!("ldxdw r1, [r2+0x3]");
+}
+
+// Example for InstructionType::StoreImm.
+#[test]
+fn test_sth() {
+    disasm!("sth [r1+0x2], 0x3");
+}
+
+// Example for InstructionType::StoreReg.
+#[test]
+fn test_stxh() {
+    disasm!("stxh [r1+0x2], r3");
+}
+
+// Test all supported AluBinary mnemonics.
+#[test]
+fn test_alu_binary() {
+    disasm!("add64 r1, r2
+sub64 r1, r2
+mul64 r1, r2
+div64 r1, r2
+or64 r1, r2
+and64 r1, r2
+lsh64 r1, r2
+rsh64 r1, r2
+mod64 r1, r2
+xor64 r1, r2
+mov64 r1, r2
+arsh64 r1, r2");
+
+    disasm!("add64 r1, 0x2
+sub64 r1, 0x2
+mul64 r1, 0x2
+div64 r1, 0x2
+or64 r1, 0x2
+and64 r1, 0x2
+lsh64 r1, 0x2
+rsh64 r1, 0x2
+mod64 r1, 0x2
+xor64 r1, 0x2
+mov64 r1, 0x2
+arsh64 r1, 0x2");
+
+    disasm!("add32 r1, r2
+sub32 r1, r2
+mul32 r1, r2
+div32 r1, r2
+or32 r1, r2
+and32 r1, r2
+lsh32 r1, r2
+rsh32 r1, r2
+mod32 r1, r2
+xor32 r1, r2
+mov32 r1, r2
+arsh32 r1, r2");
+
+    disasm!("add32 r1, 0x2
+sub32 r1, 0x2
+mul32 r1, 0x2
+div32 r1, 0x2
+or32 r1, 0x2
+and32 r1, 0x2
+lsh32 r1, 0x2
+rsh32 r1, 0x2
+mod32 r1, 0x2
+xor32 r1, 0x2
+mov32 r1, 0x2
+arsh32 r1, 0x2");
+}
+
+// Test all supported AluUnary mnemonics.
+#[test]
+fn test_alu_unary() {
+    disasm!("neg64 r1
+neg32 r1");
+}
+
+// Test all supported LoadAbs mnemonics.
+#[test]
+fn test_load_abs() {
+    disasm!("ldabsw 0x1
+ldabsh 0x1
+ldabsb 0x1
+ldabsdw 0x1");
+}
+
+// Test all supported LoadInd mnemonics.
+#[test]
+fn test_load_ind() {
+    disasm!("ldindw r1, 0x2
+ldindh r1, 0x2
+ldindb r1, 0x2
+ldinddw r1, 0x2");
+}
+
+// Test all supported LoadReg mnemonics.
+#[test]
+fn test_load_reg() {
+    disasm!(r"ldxw r1, [r2+0x3]
+ldxh r1, [r2+0x3]
+ldxb r1, [r2+0x3]
+ldxdw r1, [r2+0x3]");
+}
+
+// Test all supported StoreImm mnemonics.
+#[test]
+fn test_store_imm() {
+    disasm!("stw [r1+0x2], 0x3
+sth [r1+0x2], 0x3
+stb [r1+0x2], 0x3
+stdw [r1+0x2], 0x3");
+}
+
+// Test all supported StoreReg mnemonics.
+#[test]
+fn test_store_reg() {
+    disasm!("stxw [r1+0x2], r3
+stxh [r1+0x2], r3
+stxb [r1+0x2], r3
+stxdw [r1+0x2], r3");
+}
+
+// Test all supported JumpConditional mnemonics.
+#[test]
+fn test_jump_conditional() {
+    disasm!("jeq r1, r2, +0x3
+jgt r1, r2, +0x3
+jge r1, r2, +0x3
+jset r1, r2, +0x3
+jne r1, r2, +0x3
+jsgt r1, r2, +0x3
+jsge r1, r2, +0x3");
+
+    disasm!("jeq r1, 0x2, +0x3
+jgt r1, 0x2, +0x3
+jge r1, 0x2, +0x3
+jset r1, 0x2, +0x3
+jne r1, 0x2, +0x3
+jsgt r1, 0x2, +0x3
+jsge r1, 0x2, +0x3");
+}
+
+// Test all supported Endian mnemonics.
+#[test]
+fn test_endian() {
+    disasm!("be16 r1
+be32 r1
+be64 r1
+le16 r1
+le32 r1
+le64 r1");
+}
+
+#[test]
+fn test_large_immediate() {
+    disasm!("add64 r1, 0x7fffffff");
+    disasm!("add64 r1, 0x7fffffff");
+}