Skip to content
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

[WIP] Compile-time Target Architecture Tags #143

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,33 @@ See the [`capstone-sys`](capstone-sys) page for the requirements and supported p
```rust
extern crate capstone;

use capstone::arch::x86::X86ArchTag;
use capstone::prelude::*;

const X86_CODE: &'static [u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\x14\x9e\x08\x00\x45\x31\xe4";

/// 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();
fn reg_names<A, I>(cs: &Capstone<A>, regs: I) -> String
where
A: ArchTag,
I: Iterator<Item = A::RegId>,
{
let names: Vec<String> = regs.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();
fn group_names<A, I>(cs: &Capstone<A>, regs: I) -> String
where
A: ArchTag,
I: Iterator<Item = A::InsnGroupId>,
{
let names: Vec<String> = regs.map(|x| cs.group_name(x).unwrap()).collect();
names.join(", ")
}

fn main() {
let cs = Capstone::new()
.x86()
let cs = Capstone::<X86ArchTag>::new()
.mode(arch::x86::ArchMode::Mode64)
.syntax(arch::x86::ArchSyntax::Att)
.detail(true)
Expand All @@ -63,8 +71,8 @@ fn main() {
println!();
println!("{}", i);

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

let output: &[(&str, String)] = &[
Expand Down
5 changes: 3 additions & 2 deletions capstone-rs/benches/my_benchmark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ extern crate capstone;
#[macro_use]
extern crate criterion;

use capstone::arch::DynamicArchTag;
use capstone::prelude::*;
use capstone::{Arch, Endian, ExtraMode, Mode, NO_EXTRA_MODE};
use criterion::{black_box, Criterion};
Expand All @@ -17,8 +18,8 @@ fn arch_bench<T: Iterator<Item = ExtraMode>>(
endian: Option<Endian>,
detail: bool,
) {
let mut cs =
Capstone::new_raw(arch, mode, extra_mode, endian).expect("failed to make capstone");
let mut cs = Capstone::<DynamicArchTag>::new_raw(arch, mode, extra_mode, endian)
.expect("failed to make capstone");
cs.set_detail(detail).expect("failed to set detail");

let insns = cs.disasm_all(code, 0x1000).expect("failed to disassemble");
Expand Down
46 changes: 26 additions & 20 deletions capstone-rs/examples/demo.rs
Original file line number Diff line number Diff line change
@@ -1,37 +1,50 @@
extern crate capstone;

use capstone::arch::mips::MipsArchTag;
use capstone::arch::x86::X86ArchTag;
use capstone::arch::{ArchTag, DetailsArchInsn};
use capstone::prelude::*;
use capstone::InsnDetail;

const MIPS_CODE: &[u8] = b"\x56\x34\x21\x34\xc2\x17\x01\x00";

const X86_CODE: &[u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\x14\x9e\x08\x00\x45\x31\xe4";

#[cfg(feature = "full")]
/// 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();
fn reg_names<A, I>(cs: &Capstone<A>, regs: I) -> String
where
A: ArchTag,
I: Iterator<Item = A::RegId>,
{
let names: Vec<String> = regs.map(|x| cs.reg_name(x).unwrap()).collect();
names.join(", ")
}

#[cfg(feature = "full")]
/// 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();
fn group_names<A, I>(cs: &Capstone<A>, regs: I) -> String
where
A: ArchTag,
I: Iterator<Item = A::InsnGroupId>,
{
let names: Vec<String> = regs.map(|x| cs.group_name(x).unwrap()).collect();
names.join(", ")
}

/// Disassemble code and print information
fn arch_example(cs: &mut Capstone, code: &[u8]) -> CsResult<()> {
fn arch_example<A: ArchTag>(arch: &'static str, cs: &mut Capstone<A>, code: &[u8]) -> CsResult<()> {
println!("\n*************************************");
println!("Architecture {}:", arch);

let insns = cs.disasm_all(code, 0x1000)?;
println!("Found {} instructions", insns.len());
for i in insns.iter() {
println!();
println!("{}", i);

let detail: InsnDetail = cs.insn_detail(i)?;
let arch_detail: ArchDetail = detail.arch_detail();
let ops = arch_detail.operands();
let detail = cs.insn_detail(i)?;
let arch_detail = detail.arch_detail();
let ops: Vec<_> = arch_detail.operands().collect();

#[cfg(feature = "full")]
let output: &[(&str, String)] = &[
Expand Down Expand Up @@ -61,26 +74,19 @@ fn arch_example(cs: &mut Capstone, code: &[u8]) -> CsResult<()> {
}

fn example() -> CsResult<()> {
let cs_mips: Capstone = Capstone::new()
.mips()
let mut cs_mips = Capstone::<MipsArchTag>::new()
.mode(arch::mips::ArchMode::Mips32R6)
.detail(true)
.build()?;

let cs_x86 = Capstone::new()
.x86()
let mut cs_x86 = Capstone::<X86ArchTag>::new()
.mode(arch::x86::ArchMode::Mode64)
.syntax(arch::x86::ArchSyntax::Att)
.detail(true)
.build()?;

let mut examples = [("MIPS", cs_mips, MIPS_CODE), ("X86", cs_x86, X86_CODE)];

for &mut (arch, ref mut cs, code) in examples.iter_mut() {
println!("\n*************************************");
println!("Architecture {}:", arch);
arch_example(cs, code)?;
}
arch_example("MIPS", &mut cs_mips, MIPS_CODE)?;
arch_example("X86", &mut cs_x86, X86_CODE)?;

Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions capstone-rs/examples/objdump.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
extern crate capstone;
extern crate macho;

use capstone::arch::x86::X86ArchTag;
use capstone::prelude::*;
use std::env;
use std::fs;
use std::io::Read;
use std::process;

fn main() {
let cs = Capstone::new()
.x86()
let cs = Capstone::<X86ArchTag>::new()
.mode(arch::x86::ArchMode::Mode64)
.build()
.expect("Failed to create capstone handle");
Expand Down
6 changes: 3 additions & 3 deletions capstone-rs/examples/parallel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
//!
//! We shard the input by using parallel iterators from the rayon crate.

use capstone::arch::x86::X86ArchTag;
use capstone::prelude::*;
use rayon::prelude::*;

fn main() -> CsResult<()> {
// Closure to create `Capstone` instance
let create_cs = || -> CsResult<Capstone> {
let cs = Capstone::new()
.x86()
let create_cs = || -> CsResult<Capstone<X86ArchTag>> {
let cs = Capstone::<X86ArchTag>::new()
.mode(arch::x86::ArchMode::Mode64)
.detail(true)
.build()?;
Expand Down
8 changes: 4 additions & 4 deletions capstone-rs/fuzz/fuzz_targets/fuzz_target_disasm_x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@
extern crate libfuzzer_sys;
extern crate capstone;

use capstone::arch::x86::X86ArchTag;
use capstone::prelude::*;

fuzz_target!(|data: &[u8]| {
let mut cs = Capstone::new()
.x86()
let mut cs = Capstone::<X86ArchTag>::new()
.mode(arch::x86::ArchMode::Mode64)
.detail(true)
.build()
.unwrap();
for i in cs.disasm_all(data, 0x1000).unwrap().iter() {
let detail: InsnDetail = cs.insn_detail(&i).unwrap();
let arch_detail: ArchDetail = detail.arch_detail();
let detail = cs.insn_detail(&i).unwrap();
let arch_detail = detail.arch_detail();
arch_detail.operands().iter().for_each(drop);
detail.regs_read().iter().for_each(drop);
detail.regs_write().iter().for_each(drop);
Expand Down
42 changes: 36 additions & 6 deletions capstone-rs/src/arch/arm.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
//! Contains arm-specific types

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

use capstone_sys::{
arm_op_mem, arm_op_type, cs_arm, cs_arm_op, arm_shifter,
cs_arm_op__bindgen_ty_2};
use libc::c_uint;

pub use crate::arch::arch_builder::arm::*;
use crate::arch::DetailsArchInsn;
use crate::arch::{ArchTag, DetailsArchInsn};
use crate::arch::internal::ArchTagSealed;
use crate::instruction::{RegId, RegIdInt};
use crate::{Arch, InsnDetail};

pub use capstone_sys::arm_insn_group as ArmInsnGroup;
pub use capstone_sys::arm_insn as ArmInsn;
Expand All @@ -22,9 +23,38 @@ pub use capstone_sys::arm_cc as ArmCC;
pub use capstone_sys::arm_mem_barrier as ArmMemBarrier;
pub use capstone_sys::arm_setend_type as ArmSetendType;

/// Architecture tag that represents ARM.
pub struct ArmArchTag;

impl ArchTagSealed for ArmArchTag {}

impl ArchTag for ArmArchTag {
type Builder = ArchCapstoneBuilder;

type Mode = ArchMode;
type ExtraMode = ArchExtraMode;
type Syntax = ArchSyntax;

type RegId = ArmReg;
type InsnId = ArmInsn;
type InsnGroupId = ArmInsnGroup;

type InsnDetail<'a> = ArmInsnDetail<'a>;

fn support_arch(arch: Arch) -> bool {
arch == Arch::ARM
}
}

/// Contains ARM-specific details for an instruction
pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);

impl<'a, 'i> From<&'i InsnDetail<'a, ArmArchTag>> for ArmInsnDetail<'a> {
fn from(value: &'i InsnDetail<'a, ArmArchTag>) -> Self {
Self(unsafe { &value.0.__bindgen_anon_1.arm })
}
}

/// ARM shift amount
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ArmShift {
Expand Down Expand Up @@ -221,12 +251,12 @@ impl_PartialEq_repr_fields!(ArmInsnDetail<'a> [ 'a ];
impl ArmOpMem {
/// Base register
pub fn base(&self) -> RegId {
RegId(self.0.base as RegIdInt)
RegId(self.0.base.0 as RegIdInt)
}

/// Index value
pub fn index(&self) -> RegId {
RegId(self.0.index as RegIdInt)
RegId(self.0.index.0 as RegIdInt)
}

/// Scale for index register (can be 1, or -1)
Expand All @@ -244,7 +274,7 @@ impl_PartialEq_repr_fields!(ArmOpMem;
base, index, scale, disp
);

impl cmp::Eq for ArmOpMem {}
impl Eq for ArmOpMem {}

impl Default for ArmOperand {
fn default() -> Self {
Expand Down Expand Up @@ -280,7 +310,7 @@ def_arch_details_struct!(
Operand = ArmOperand;
OperandIterator = ArmOperandIterator;
OperandIteratorLife = ArmOperandIterator<'a>;
[ pub struct ArmOperandIterator<'a>(slice::Iter<'a, cs_arm_op>); ]
[ pub struct ArmOperandIterator<'a>(core::slice::Iter<'a, cs_arm_op>); ]
cs_arch_op = cs_arm_op;
cs_arch = cs_arm;
);
Expand Down
Loading