Skip to content

Commit

Permalink
Merge ce5c2c7 into 7c9a51f
Browse files Browse the repository at this point in the history
  • Loading branch information
deepaksirone committed Oct 15, 2023
2 parents 7c9a51f + ce5c2c7 commit b1f6bf9
Show file tree
Hide file tree
Showing 10 changed files with 508 additions and 84 deletions.
102 changes: 102 additions & 0 deletions capstone-rs/src/arch/bpf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
//! Contains bpf specific types

use core::convert::From;
use core::{cmp, fmt, slice};

pub use capstone_sys::bpf_insn_group as BpfInsnGroup;
pub use capstone_sys::bpf_insn as BpfInsn;
pub use capstone_sys::bpf_reg as BpfReg;
use capstone_sys::{cs_bpf, cs_bpf_op, bpf_op_mem, bpf_op_type};

pub use crate::arch::arch_builder::bpf::*;
use crate::arch::DetailsArchInsn;
use crate::instruction::{RegId, RegIdInt};

/// Contains BPF-specific details for an instruction
pub struct BpfInsnDetail<'a>(pub(crate) &'a cs_bpf);

impl_PartialEq_repr_fields!(BpfInsnDetail<'a> [ 'a ];
operands
);

/// BPF operand
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BpfOperand {
/// Register
Reg(RegId),

/// Immediate
Imm(u64),

/// Memory
Mem(BpfOpMem),

/// Offset
Off(u32),

/// Mmem
Mmem(u32),

/// Msh
Msh(u32),

/// Ext
Ext(u32),

/// Invalid
Invalid,
}

impl Default for BpfOperand {
fn default() -> Self {
BpfOperand::Invalid
}
}


/// Bpf memory operand
#[derive(Debug, Copy, Clone)]
pub struct BpfOpMem(pub(crate) bpf_op_mem);

impl BpfOpMem {
/// Base register
pub fn base(&self) -> RegId {
RegId(self.0.base as RegIdInt)
}

/// Disp value
pub fn disp(&self) -> u32 {
self.0.disp
}
}

impl_PartialEq_repr_fields!(BpfOpMem;
base, disp
);

impl cmp::Eq for BpfOpMem {}

impl<'a> From<&'a cs_bpf_op> for BpfOperand {
fn from(insn: &cs_bpf_op) -> BpfOperand {
match insn.type_ {
bpf_op_type::BPF_OP_EXT => BpfOperand::Ext(unsafe { insn.__bindgen_anon_1.ext }),
bpf_op_type::BPF_OP_INVALID => BpfOperand::Invalid,
bpf_op_type::BPF_OP_REG => BpfOperand::Reg(RegId(unsafe {insn.__bindgen_anon_1.reg} as RegIdInt)),
bpf_op_type::BPF_OP_IMM => BpfOperand::Imm(unsafe { insn.__bindgen_anon_1.imm }),
bpf_op_type::BPF_OP_MEM => BpfOperand::Mem(BpfOpMem(unsafe { insn.__bindgen_anon_1.mem})),
bpf_op_type::BPF_OP_OFF => BpfOperand::Off(unsafe { insn.__bindgen_anon_1.off }),
bpf_op_type::BPF_OP_MMEM => BpfOperand::Mmem(unsafe { insn.__bindgen_anon_1.mmem }),
bpf_op_type::BPF_OP_MSH => BpfOperand::Msh(unsafe { insn.__bindgen_anon_1.msh }),
}
}
}

def_arch_details_struct!(
InsnDetail = BpfInsnDetail;
Operand = BpfOperand;
OperandIterator = BpfOperandIterator;
OperandIteratorLife = BpfOperandIterator<'a>;
[ pub struct BpfOperandIterator<'a>(slice::Iter<'a, cs_bpf_op>); ]
cs_arch_op = cs_bpf_op;
cs_arch = cs_bpf;
);
17 changes: 17 additions & 0 deletions capstone-rs/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,16 @@ macro_rules! arch_info_base {
( syntax: )
( both_endian: false )
]
[
( bpf, BPF )
( mode:
Cbpf,
Ebpf,
)
( extra_modes: )
( syntax: )
( both_endian: true )
]
);
};
}
Expand Down Expand Up @@ -534,6 +544,13 @@ macro_rules! detail_arch_base {
/// Returns the XCore details, if any
=> arch_name = xcore,
]
[
detail = BpfDetail,
insn_detail = BpfInsnDetail<'a>,
op = BpfOperand,
/// Returns the XCore details, if any
=> arch_name = bpf,
]
);
};
}
Expand Down
6 changes: 6 additions & 0 deletions capstone-rs/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ define_cs_enum_wrapper!(
=> EVM = CS_ARCH_EVM;
/// RISC-V
=> RISCV = CS_ARCH_RISCV;
/// BPF
=> BPF = CS_ARCH_BPF;
);

define_cs_enum_wrapper!(
Expand Down Expand Up @@ -286,6 +288,10 @@ define_cs_enum_wrapper!(
=> RiscV32 = CS_MODE_RISCV32;
/// RISC-V 64-bit mode
=> RiscV64 = CS_MODE_RISCV64;
/// Classic BPF mode
=> Cbpf = CS_MODE_BPF_CLASSIC;
/// Extended BPF mode
=> Ebpf = CS_MODE_BPF_EXTENDED;
/// Default mode for little-endian
=> Default = CS_MODE_LITTLE_ENDIAN;
);
Expand Down
1 change: 1 addition & 0 deletions capstone-rs/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ impl<'a> InsnDetail<'a> {
[TMS320C64X, Tms320c64xDetail, Tms320c64xInsnDetail, tms320c64x]
[X86, X86Detail, X86InsnDetail, x86]
[XCORE, XcoreDetail, XcoreInsnDetail, xcore]
[BPF, BpfDetail, BpfInsnDetail, bpf]
);
}
}
Expand Down
107 changes: 107 additions & 0 deletions capstone-rs/src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ use super::*;

const X86_CODE: &[u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";
const ARM_CODE: &[u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00";
const CBPF_CODE: &[u8] = b"\x94\x09\x00\x00\x37\x13\x03\x00\
\x87\x00\x00\x00\x00\x00\x00\x00\
\x07\x00\x00\x00\x00\x00\x00\x00\
\x16\x00\x00\x00\x00\x00\x00\x00\
\x80\x00\x00\x00\x00\x00\x00\x00";
const EBPF_CODE: &[u8] = b"\x97\x09\x00\x00\x37\x13\x03\x00\
\xdc\x02\x00\x00\x20\x00\x00\x00\
\x30\x00\x00\x00\x00\x00\x00\x00\
\xdb\x3a\x00\x01\x00\x00\x00\x00\
\x84\x02\x00\x00\x00\x00\x00\x00\
\x6d\x33\x17\x02\x00\x00\x00\x00";

// Aliases for group types
const JUMP: cs_group_type::Type = cs_group_type::CS_GRP_JUMP;
Expand Down Expand Up @@ -3244,3 +3255,99 @@ fn test_owned_insn() {
assert_eq!(format!("{:?}", insn), format!("{:?}", owned));
}
}


/// Print register names
fn reg_names(cs: &Capstone, regs: &[RegId]) -> String {
let names: Vec<String> = regs.iter().map(|&x| cs.reg_name(x).unwrap()).collect();
names.join(", ")
}

/// Print instruction group names
fn group_names(cs: &Capstone, regs: &[InsnGroupId]) -> String {
let names: Vec<String> = regs.iter().map(|&x| cs.group_name(x).unwrap()).collect();
names.join(", ")
}

#[test]
fn test_cbpf() {
let cs = Capstone::new().bpf().mode(bpf::ArchMode::Cbpf).endian(Endian::Little).detail(true).build().unwrap();
let insns = cs.disasm_all(CBPF_CODE, 0x1000);
match insns {
Ok(ins) => {
for i in ins.as_ref() {
println!();
eprintln!("{}", i);

let detail: InsnDetail = cs.insn_detail(&i).expect("Failed to get insn detail");
let arch_detail: ArchDetail = detail.arch_detail();
let ops = arch_detail.operands();

let output: &[(&str, String)] = &[
("insn id:", format!("{:?}", i.id().0)),
("bytes:", format!("{:?}", i.bytes())),
("read regs:", reg_names(&cs, detail.regs_read())),
("write regs:", reg_names(&cs, detail.regs_write())),
("insn groups:", group_names(&cs, detail.groups())),
];

for &(ref name, ref message) in output.iter() {
eprintln!("{:4}{:12} {}", "", name, message);
}

println!("{:4}operands: {}", "", ops.len());
for op in ops {
eprintln!("{:8}{:?}", "", op);
}

}
}

Err(e) => {
eprintln!("{:?}", e);
assert!(false);
}
}

}

fn test_ebpf() {
let cs = Capstone::new().bpf().mode(bpf::ArchMode::Ebpf).endian(Endian::Little).detail(true).build().unwrap();
let insns = cs.disasm_all(EBPF_CODE, 0x1000);
match insns {
Ok(ins) => {
for i in ins.as_ref() {
println!();
eprintln!("{}", i);

let detail: InsnDetail = cs.insn_detail(&i).expect("Failed to get insn detail");
let arch_detail: ArchDetail = detail.arch_detail();
let ops = arch_detail.operands();

let output: &[(&str, String)] = &[
("insn id:", format!("{:?}", i.id().0)),
("bytes:", format!("{:?}", i.bytes())),
("read regs:", reg_names(&cs, detail.regs_read())),
("write regs:", reg_names(&cs, detail.regs_write())),
("insn groups:", group_names(&cs, detail.groups())),
];

for &(ref name, ref message) in output.iter() {
eprintln!("{:4}{:12} {}", "", name, message);
}

println!("{:4}operands: {}", "", ops.len());
for op in ops {
eprintln!("{:8}{:?}", "", op);
}

}
}

Err(e) => {
eprintln!("{:?}", e);
assert!(false);
}
}

}
2 changes: 1 addition & 1 deletion capstone-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ travis-ci = { repository = "capstone-rust/capstone-sys" }
libc = { version = "0.2.59", default-features = false }

[build-dependencies]
bindgen = { optional = true, version = "0.59.1" }
bindgen = { optional = true, version = "0.62.0" }
regex = { optional = true, version = "1.3.1" }
cc = "1.0"

Expand Down
3 changes: 2 additions & 1 deletion capstone-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ fn build_capstone_cc() {
.define("CAPSTONE_HAS_WASM", None)
.define("CAPSTONE_HAS_X86", None)
.define("CAPSTONE_HAS_XCORE", None)
.define("CAPSTONE_HAS_BPF", None)
// No need to display any warnings from the C library
.flag_if_supported("-w")
.static_crt(use_static_crt);
Expand Down Expand Up @@ -282,7 +283,7 @@ fn write_bindgen_bindings(
bindings
.write_to_file(&out_bindings_path)
.expect("Unable to write bindings");

// Parse bindings and impl fn to cast u32 to <arch>_insn, write output to file
let bindings_impl_str = impl_insid_to_insenum(&bindings.to_string());
let mut bindings_impl = File::create(&out_impl_path).expect("Unable to open file");
Expand Down
4 changes: 4 additions & 0 deletions capstone-sys/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ pub static ARCH_INCLUDES: &[CapstoneArchInfo<'static>] = &[
header_name: "xcore.h",
cs_name: "xcore",
},
CapstoneArchInfo {
header_name: "bpf.h",
cs_name: "bpf"
}
];

pub static BINDINGS_FILE: &str = "capstone.rs";
Expand Down
Loading

0 comments on commit b1f6bf9

Please sign in to comment.