Skip to content

Commit a59909c

Browse files
committed
Make unit tests compile and pass all tests
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.
1 parent 3422ee7 commit a59909c

File tree

9 files changed

+150
-111
lines changed

9 files changed

+150
-111
lines changed

README.md

+16-8
Original file line numberDiff line numberDiff line change
@@ -31,25 +31,33 @@ See the [`capstone-sys`](capstone-sys) page for the requirements and supported p
3131
```rust
3232
extern crate capstone;
3333

34+
use capstone::arch::x86::X86ArchTag;
3435
use capstone::prelude::*;
3536

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

3839
/// Print register names
39-
fn reg_names(cs: &Capstone, regs: &[RegId]) -> String {
40-
let names: Vec<String> = regs.iter().map(|&x| cs.reg_name(x).unwrap()).collect();
40+
fn reg_names<A, I>(cs: &Capstone<A>, regs: I) -> String
41+
where
42+
A: ArchTag,
43+
I: Iterator<Item = A::RegId>,
44+
{
45+
let names: Vec<String> = regs.map(|x| cs.reg_name(x).unwrap()).collect();
4146
names.join(", ")
4247
}
4348

4449
/// Print instruction group names
45-
fn group_names(cs: &Capstone, regs: &[InsnGroupId]) -> String {
46-
let names: Vec<String> = regs.iter().map(|&x| cs.group_name(x).unwrap()).collect();
50+
fn group_names<A, I>(cs: &Capstone<A>, regs: I) -> String
51+
where
52+
A: ArchTag,
53+
I: Iterator<Item = A::InsnGroupId>,
54+
{
55+
let names: Vec<String> = regs.map(|x| cs.group_name(x).unwrap()).collect();
4756
names.join(", ")
4857
}
4958

5059
fn main() {
51-
let cs = Capstone::new()
52-
.x86()
60+
let cs = Capstone::<X86ArchTag>::new()
5361
.mode(arch::x86::ArchMode::Mode64)
5462
.syntax(arch::x86::ArchSyntax::Att)
5563
.detail(true)
@@ -63,8 +71,8 @@ fn main() {
6371
println!();
6472
println!("{}", i);
6573

66-
let detail: InsnDetail = cs.insn_detail(&i).expect("Failed to get insn detail");
67-
let arch_detail: ArchDetail = detail.arch_detail();
74+
let detail = cs.insn_detail(&i).expect("Failed to get insn detail");
75+
let arch_detail = detail.arch_detail();
6876
let ops = arch_detail.operands();
6977

7078
let output: &[(&str, String)] = &[

capstone-rs/examples/demo.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,23 @@ const X86_CODE: &[u8] = b"\x55\x48\x8b\x05\xb8\x13\x00\x00\xe9\x14\x9e\x08\x00\x
1111

1212
#[cfg(feature = "full")]
1313
/// Print register names
14-
fn reg_names<A: ArchTag>(cs: &Capstone<A>, regs: &[A::RegId]) -> String {
15-
let names: Vec<String> = regs.iter().map(|&x| cs.reg_name(x).unwrap()).collect();
14+
fn reg_names<A, I>(cs: &Capstone<A>, regs: I) -> String
15+
where
16+
A: ArchTag,
17+
I: Iterator<Item = A::RegId>,
18+
{
19+
let names: Vec<String> = regs.map(|x| cs.reg_name(x).unwrap()).collect();
1620
names.join(", ")
1721
}
1822

1923
#[cfg(feature = "full")]
2024
/// Print instruction group names
21-
fn group_names<A: ArchTag>(cs: &Capstone<A>, regs: &[A::InsnGroupId]) -> String {
22-
let names: Vec<String> = regs.iter().map(|&x| cs.group_name(x).unwrap()).collect();
25+
fn group_names<A, I>(cs: &Capstone<A>, regs: I) -> String
26+
where
27+
A: ArchTag,
28+
I: Iterator<Item = A::InsnGroupId>,
29+
{
30+
let names: Vec<String> = regs.map(|x| cs.group_name(x).unwrap()).collect();
2331
names.join(", ")
2432
}
2533

capstone-rs/fuzz/fuzz_targets/fuzz_target_disasm_x86_64.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
extern crate libfuzzer_sys;
44
extern crate capstone;
55

6+
use capstone::arch::x86::X86ArchTag;
67
use capstone::prelude::*;
78

89
fuzz_target!(|data: &[u8]| {
9-
let mut cs = Capstone::new()
10-
.x86()
10+
let mut cs = Capstone::<X86ArchTag>::new()
1111
.mode(arch::x86::ArchMode::Mode64)
1212
.detail(true)
1313
.build()
1414
.unwrap();
1515
for i in cs.disasm_all(data, 0x1000).unwrap().iter() {
16-
let detail: InsnDetail = cs.insn_detail(&i).unwrap();
17-
let arch_detail: ArchDetail = detail.arch_detail();
16+
let detail = cs.insn_detail(&i).unwrap();
17+
let arch_detail = detail.arch_detail();
1818
arch_detail.operands().iter().for_each(drop);
1919
detail.regs_read().iter().for_each(drop);
2020
detail.regs_write().iter().for_each(drop);

capstone-rs/src/arch/evm.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ pub use capstone_sys::evm_insn as EvmInsn;
1212
pub use crate::arch::arch_builder::evm::*;
1313
use crate::arch::{ArchTag, DetailsArchInsn};
1414
use crate::arch::internal::ArchTagSealed;
15-
use crate::{Arch, InsnDetail};
15+
use crate::{Arch, InsnDetail, RegIdInt};
1616

1717
pub struct EvmArchTag;
1818

@@ -25,7 +25,7 @@ impl ArchTag for EvmArchTag {
2525
type ExtraMode = ArchExtraMode;
2626
type Syntax = ArchSyntax;
2727

28-
type RegId = u32;
28+
type RegId = RegIdInt;
2929
type InsnId = EvmInsn;
3030
type InsnGroupId = EvmInsnGroup;
3131

capstone-rs/src/arch/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,9 @@ pub trait ArchTag: internal::ArchTagSealed + 'static + Sized {
361361
type ExtraMode: Copy + Into<ExtraMode>;
362362
type Syntax: Copy + Into<Syntax>;
363363

364-
type RegId: Copy + Into<RegId>;
364+
type RegId: Copy + From<RegId> + Into<RegId>;
365365
type InsnId: Copy + Into<InsnId>;
366-
type InsnGroupId: Copy + Into<InsnGroupId>;
366+
type InsnGroupId: Copy + From<InsnGroupId> + Into<InsnGroupId>;
367367

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

capstone-rs/src/capstone.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,9 @@ impl<A: ArchTag> Capstone<A> {
121121
/// This is the recommended interface to `Capstone`.
122122
///
123123
/// ```
124+
/// use capstone::arch::x86::X86ArchTag;
124125
/// use capstone::prelude::*;
125-
/// let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build();
126+
/// let cs = Capstone::<X86ArchTag>::new().mode(arch::x86::ArchMode::Mode32).build();
126127
/// ```
127128
#[allow(clippy::new_ret_no_self)]
128129
pub fn new() -> A::Builder {
@@ -134,7 +135,8 @@ impl<A: ArchTag> Capstone<A> {
134135
///
135136
/// ```
136137
/// use capstone::{Arch, Capstone, NO_EXTRA_MODE, Mode};
137-
/// let cs = Capstone::new_raw(Arch::X86, Mode::Mode64, NO_EXTRA_MODE, None);
138+
/// use capstone::arch::DynamicArchTag;
139+
/// let cs = Capstone::<DynamicArchTag>::new_raw(Arch::X86, Mode::Mode64, NO_EXTRA_MODE, None);
138140
/// assert!(cs.is_ok());
139141
/// ```
140142
pub fn new_raw<T: Iterator<Item = ExtraMode>>(
@@ -191,7 +193,8 @@ impl<A: ArchTag> Capstone<A> {
191193
///
192194
/// ```
193195
/// # use capstone::prelude::*;
194-
/// # let cs = Capstone::new().x86().mode(arch::x86::ArchMode::Mode32).build().unwrap();
196+
/// # use capstone::arch::x86::X86ArchTag;
197+
/// # let cs = Capstone::<X86ArchTag>::new().mode(arch::x86::ArchMode::Mode32).build().unwrap();
195198
/// cs.disasm_all(b"\x90", 0x1000).unwrap();
196199
/// ```
197200
pub fn disasm_all<'a>(&'a self, code: &[u8], addr: u64) -> CsResult<Instructions<'a, A>> {

0 commit comments

Comments
 (0)