Skip to content

Commit

Permalink
Make unit tests compile and pass all tests
Browse files Browse the repository at this point in the history
This commit fixes a minor problem that prevents tests from compiling and running
to success.

Arch-specific register IDs (represented by ArchTag::RegId) and instruction group
IDs (represented by ArchTag::InsnGroupId) are generated as newtype structs whose
inner type is c_uint because their C definition are just C enums. However, in a
cs_detail struct, the regs_read field is an array of u16, not an array of
c_uint. So we cannot just type pun on the underlying array to get &[A::RegId]
because the layout is totally different. The similar problem exists for
InsnDetail::regs_write and InsnDetail::groups.

This commit fixes the problem by making these function return an Iterator rather
than a slice. The iterator will map the underlying array elements to actual
arch-specific types when iterated.
  • Loading branch information
Lancern committed Aug 31, 2023
1 parent 3422ee7 commit 445e43a
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 111 deletions.
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
16 changes: 12 additions & 4 deletions capstone-rs/examples/demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,23 @@ const X86_CODE: &[u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\x14\x9e\x08\x00\x

#[cfg(feature = "full")]
/// Print register names
fn reg_names<A: ArchTag>(cs: &Capstone<A>, regs: &[A::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<A: ArchTag>(cs: &Capstone<A>, regs: &[A::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(", ")
}

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
4 changes: 2 additions & 2 deletions capstone-rs/src/arch/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub use capstone_sys::evm_insn as EvmInsn;
pub use crate::arch::arch_builder::evm::*;
use crate::arch::{ArchTag, DetailsArchInsn};
use crate::arch::internal::ArchTagSealed;
use crate::{Arch, InsnDetail};
use crate::{Arch, InsnDetail, RegIdInt};

pub struct EvmArchTag;

Expand All @@ -25,7 +25,7 @@ impl ArchTag for EvmArchTag {
type ExtraMode = ArchExtraMode;
type Syntax = ArchSyntax;

type RegId = u32;
type RegId = RegIdInt;
type InsnId = EvmInsn;
type InsnGroupId = EvmInsnGroup;

Expand Down
4 changes: 2 additions & 2 deletions capstone-rs/src/arch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -361,9 +361,9 @@ pub trait ArchTag: internal::ArchTagSealed + 'static + Sized {
type ExtraMode: Copy + Into<ExtraMode>;
type Syntax: Copy + Into<Syntax>;

type RegId: Copy + Into<RegId>;
type RegId: Copy + From<RegId> + Into<RegId>;
type InsnId: Copy + Into<InsnId>;
type InsnGroupId: Copy + Into<InsnGroupId>;
type InsnGroupId: Copy + From<InsnGroupId> + Into<InsnGroupId>;

type InsnDetail<'a>: DetailsArchInsn + for<'i> From<&'i InsnDetail<'a, Self>>;

Expand Down
9 changes: 6 additions & 3 deletions capstone-rs/src/capstone.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ impl<A: ArchTag> Capstone<A> {
/// This is the recommended interface to `Capstone`.
///
/// ```
/// use capstone::arch::x86::X86ArchTag;
/// use capstone::prelude::*;
/// let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build();
/// let cs = Capstone::<X86ArchTag>::new().mode(arch::x86::ArchMode::Mode32).build();
/// ```
#[allow(clippy::new_ret_no_self)]
pub fn new() -> A::Builder {
Expand All @@ -134,7 +135,8 @@ impl<A: ArchTag> Capstone<A> {
///
/// ```
/// use capstone::{Arch, Capstone, NO_EXTRA_MODE, Mode};
/// let cs = Capstone::new_raw(Arch::X86, Mode::Mode64, NO_EXTRA_MODE, None);
/// use capstone::arch::DynamicArchTag;
/// let cs = Capstone::<DynamicArchTag>::new_raw(Arch::X86, Mode::Mode64, NO_EXTRA_MODE, None);
/// assert!(cs.is_ok());
/// ```
pub fn new_raw<T: Iterator<Item = ExtraMode>>(
Expand Down Expand Up @@ -191,7 +193,8 @@ impl<A: ArchTag> Capstone<A> {
///
/// ```
/// # use capstone::prelude::*;
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
/// # use capstone::arch::x86::X86ArchTag;
/// # let cs = Capstone::<X86ArchTag>::new().mode(arch::x86::ArchMode::Mode32).build().unwrap();
/// cs.disasm_all(b"\x90", 0x1000).unwrap();
/// ```
pub fn disasm_all<'a>(&'a self, code: &[u8], addr: u64) -> CsResult<Instructions<'a, A>> {
Expand Down
Loading

0 comments on commit 445e43a

Please sign in to comment.