-
Notifications
You must be signed in to change notification settings - Fork 85
Add Support for BPF arch #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
); |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -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; | ||||
|
@@ -3244,3 +3255,185 @@ 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); | ||||
tmfink marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
} | ||||
} | ||||
} | ||||
|
||||
#[test] | ||||
fn test_ebpf() { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also add a test function capstone-rs/capstone-rs/src/test.rs Line 2681 in 7c9a51f
|
||||
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); | ||||
tmfink marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
} | ||||
} | ||||
} | ||||
|
||||
#[test] | ||||
fn test_arch_bpf_detail() { | ||||
use crate::arch::bpf::BpfOperand::*; | ||||
use crate::arch::bpf::BpfReg::*; | ||||
use crate::arch::bpf::*; | ||||
use capstone_sys::*; | ||||
|
||||
test_arch_mode_endian_insns_detail( | ||||
&mut Capstone::new() | ||||
.bpf() | ||||
.mode(bpf::ArchMode::Ebpf) | ||||
.endian(Endian::Little) | ||||
.detail(true) | ||||
.build() | ||||
.unwrap(), | ||||
Arch::BPF, | ||||
Mode::Ebpf, | ||||
None, | ||||
&[], | ||||
&[ | ||||
// r1 = 0x1 | ||||
DII::new( | ||||
"mov64", | ||||
b"\xb7\x01\x00\x00\x01\x00\x00\x00", | ||||
&[Reg(RegId(BPF_REG_R1 as RegIdInt)), Imm(1)], | ||||
), | ||||
// r0 = *(u32 *)(r10 - 0xc) | ||||
DII::new( | ||||
"ldxw", | ||||
b"\x61\xa0\xf4\xff\x00\x00\x00\x00", | ||||
&[ | ||||
Reg(RegId(BPF_REG_R0 as RegIdInt)), | ||||
Mem(BpfOpMem(bpf_op_mem { | ||||
base: BPF_REG_R10, | ||||
disp: 0xfff4, | ||||
})), | ||||
], | ||||
), | ||||
// *(u32 *)(r10 - 0xc) = r1 | ||||
DII::new( | ||||
"stxw", | ||||
b"\x63\x1a\xf4\xff\x00\x00\x00\x00", | ||||
&[ | ||||
Mem(BpfOpMem(bpf_op_mem { | ||||
base: BPF_REG_R10, | ||||
disp: 0xfff4, | ||||
})), | ||||
Reg(RegId(BPF_REG_R1 as RegIdInt)), | ||||
], | ||||
), | ||||
// exit | ||||
DII::new("exit", b"\x95\x00\x00\x00\x00\x00\x00\x00", &[]), | ||||
], | ||||
); | ||||
|
||||
test_arch_mode_endian_insns_detail( | ||||
&mut Capstone::new() | ||||
.bpf() | ||||
.mode(bpf::ArchMode::Cbpf) | ||||
.endian(Endian::Little) | ||||
.detail(true) | ||||
.build() | ||||
.unwrap(), | ||||
Arch::BPF, | ||||
Mode::Cbpf, | ||||
None, | ||||
&[], | ||||
&[ | ||||
DII::new("txa", b"\x87\x00\x00\x00\x00\x00\x00\x00", &[]), | ||||
DII::new( | ||||
"ret", | ||||
b"\x16\x00\x00\x00\x00\x00\x00\x00", | ||||
&[Reg(RegId(BPF_REG_A as RegIdInt))], | ||||
), | ||||
], | ||||
); | ||||
} |
Uh oh!
There was an error while loading. Please reload this page.