Skip to content

Commit d8398a4

Browse files
committed
rs: add Xtensa arch support
1 parent 897f845 commit d8398a4

File tree

8 files changed

+259
-19
lines changed

8 files changed

+259
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313
- Alpha arch support
1414
- HPPA arch support
1515
- LoongArch arch support
16+
- Xtensa arch support
1617
- Arch-specific features flags to enable/disable arch support
1718
- Expose X86 instruction encoding info via `X86InsnDetail::encoding()`
1819
- Make RegAccessType available for ARM64

capstone-rs/src/arch/mod.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,15 @@ macro_rules! arch_info_base {
458458
( syntax: )
459459
( both_endian: false )
460460
]
461+
[
462+
( xtensa, XTENSA, "arch_xtensa" )
463+
( mode:
464+
Default,
465+
)
466+
( extra_modes: )
467+
( syntax: )
468+
( both_endian: false )
469+
]
461470
);
462471
};
463472
}
@@ -676,6 +685,14 @@ macro_rules! detail_arch_base {
676685
/// Returns the SPARC details, if any
677686
=> arch_name = sparc,
678687
]
688+
[
689+
detail = SystemZDetail,
690+
insn_detail = SystemZInsnDetail<'a>,
691+
op = SystemZOperand,
692+
feature = "arch_systemz",
693+
/// Returns the SystemZ details, if any
694+
=> arch_name = systemz,
695+
]
679696
[
680697
detail = Tms320c64xDetail,
681698
insn_detail = Tms320c64xInsnDetail<'a>,
@@ -709,12 +726,12 @@ macro_rules! detail_arch_base {
709726
=> arch_name = xcore,
710727
]
711728
[
712-
detail = SystemZDetail,
713-
insn_detail = SystemZInsnDetail<'a>,
714-
op = SystemZOperand,
715-
feature = "arch_systemz",
716-
/// Returns the SystemZ details, if any
717-
=> arch_name = systemz,
729+
detail = XtensaDetail,
730+
insn_detail = XtensaInsnDetail<'a>,
731+
op = XtensaOperand,
732+
feature = "arch_xtensa",
733+
/// Returns the HPPA details, if any
734+
=> arch_name = xtensa,
718735
]
719736
);
720737
};

capstone-rs/src/arch/xtensa.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//! Contains xtensa-specific types
2+
3+
use core::convert::{From, TryInto};
4+
use core::{cmp, fmt, slice};
5+
6+
pub use capstone_sys::xtensa_insn as XtensaInsn;
7+
pub use capstone_sys::xtensa_reg as XtensaReg;
8+
use capstone_sys::{
9+
cs_ac_type, cs_xtensa, cs_xtensa_op, cs_xtensa_op_mem, cs_xtensa_op_type,
10+
cs_xtensa_operand__bindgen_ty_1,
11+
};
12+
13+
pub use crate::arch::arch_builder::xtensa::*;
14+
use crate::arch::DetailsArchInsn;
15+
use crate::instruction::{RegId, RegIdInt};
16+
use crate::RegAccessType;
17+
18+
/// Contains xtensa-specific details for an instruction
19+
pub struct XtensaInsnDetail<'a>(pub(crate) &'a cs_xtensa);
20+
21+
impl_PartialEq_repr_fields!(XtensaInsnDetail<'a> [ 'a ];
22+
operands
23+
);
24+
25+
/// xtensa operand
26+
#[derive(Clone, Debug, Eq, PartialEq, Default)]
27+
pub struct XtensaOperand {
28+
/// Operand type
29+
pub op_type: XtensaOperandType,
30+
31+
/// How is this operand accessed?
32+
///
33+
/// NOTE: this field is always `None` if the "full" feataure is not enabled.
34+
pub access: Option<RegAccessType>,
35+
}
36+
37+
impl From<&cs_xtensa_op> for XtensaOperand {
38+
fn from(op: &cs_xtensa_op) -> XtensaOperand {
39+
let op_type = XtensaOperandType::new(op.type_, op.__bindgen_anon_1);
40+
XtensaOperand {
41+
op_type,
42+
access: cs_ac_type(op.access as _).try_into().ok(),
43+
}
44+
}
45+
}
46+
47+
/// Xtensa operand
48+
#[derive(Clone, Debug, PartialEq)]
49+
pub enum XtensaOperandType {
50+
/// Register
51+
Reg(RegId),
52+
53+
/// Immediate
54+
Imm(i32),
55+
56+
/// Memory
57+
Mem(XtensaOpMem),
58+
59+
/// Memory register
60+
MemReg(RegId),
61+
62+
/// Memory immediate
63+
MemImm(i32),
64+
65+
/// L32R target
66+
L32R(i32),
67+
68+
/// Invalid
69+
Invalid,
70+
}
71+
72+
impl XtensaOperandType {
73+
fn new(op_type: u8, value: cs_xtensa_operand__bindgen_ty_1) -> XtensaOperandType {
74+
match op_type as u32 {
75+
cs_xtensa_op_type::XTENSA_OP_REG => {
76+
XtensaOperandType::Reg(RegId(unsafe { value.reg } as RegIdInt))
77+
}
78+
cs_xtensa_op_type::XTENSA_OP_IMM => XtensaOperandType::Imm(unsafe { value.imm }),
79+
cs_xtensa_op_type::XTENSA_OP_MEM => {
80+
XtensaOperandType::Mem(XtensaOpMem(unsafe { value.mem }))
81+
}
82+
cs_xtensa_op_type::XTENSA_OP_MEM_REG => {
83+
XtensaOperandType::MemReg(RegId(unsafe { value.reg } as RegIdInt))
84+
}
85+
cs_xtensa_op_type::XTENSA_OP_MEM_IMM => XtensaOperandType::MemImm(unsafe { value.imm }),
86+
cs_xtensa_op_type::XTENSA_OP_L32R => XtensaOperandType::L32R(unsafe { value.imm }),
87+
_ => XtensaOperandType::Invalid,
88+
}
89+
}
90+
}
91+
92+
impl cmp::Eq for XtensaOperandType {}
93+
94+
impl Default for XtensaOperandType {
95+
fn default() -> Self {
96+
XtensaOperandType::Invalid
97+
}
98+
}
99+
100+
/// xtensa memory operand
101+
#[derive(Debug, Copy, Clone)]
102+
pub struct XtensaOpMem(pub(crate) cs_xtensa_op_mem);
103+
104+
impl XtensaOpMem {
105+
/// Base register
106+
pub fn base(&self) -> RegId {
107+
RegId(self.0.base as RegIdInt)
108+
}
109+
110+
/// Displacement/offset
111+
pub fn disp(&self) -> i32 {
112+
self.0.disp
113+
}
114+
}
115+
116+
impl_PartialEq_repr_fields!(XtensaOpMem;
117+
base, disp
118+
);
119+
120+
impl cmp::Eq for XtensaOpMem {}
121+
122+
def_arch_details_struct!(
123+
InsnDetail = XtensaInsnDetail;
124+
Operand = XtensaOperand;
125+
OperandIterator = XtensaOperandIterator;
126+
OperandIteratorLife = XtensaOperandIterator<'a>;
127+
[ pub struct XtensaOperandIterator<'a>(slice::Iter<'a, cs_xtensa_op>); ]
128+
cs_arch_op = cs_xtensa_op;
129+
cs_arch = cs_xtensa;
130+
);

capstone-rs/src/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ define_cs_enum_wrapper!(
236236
=> RISCV = CS_ARCH_RISCV;
237237
/// BPF
238238
=> BPF = CS_ARCH_BPF;
239+
/// XTENSA
240+
=> XTENSA = CS_ARCH_XTENSA;
239241
);
240242

241243
define_cs_enum_wrapper!(

capstone-rs/src/instruction.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ impl InsnDetail<'_> {
516516
[TRICORE, TriCoreDetail, TriCoreInsnDetail, tricore, "arch_tricore"]
517517
[X86, X86Detail, X86InsnDetail, x86, "arch_x86"]
518518
[XCORE, XcoreDetail, XcoreInsnDetail, xcore, "arch_xcore"]
519+
[XTENSA, XtensaDetail, XtensaInsnDetail, xtensa, "arch_xtensa"]
519520
);
520521
}
521522
}

capstone-rs/src/test.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,8 +2020,8 @@ fn test_arch_hppa() {
20202020
#[cfg(feature = "arch_hppa")]
20212021
#[test]
20222022
fn test_arch_hppa_detail() {
2023-
use crate::arch::hppa::{HppaMem, HppaOperand};
2024-
use capstone_sys::{cs_ac_type, hppa_mem, hppa_reg::*};
2023+
use crate::arch::hppa::HppaOperand;
2024+
use capstone_sys::hppa_reg::*;
20252025

20262026
test_arch_mode_endian_insns_detail(
20272027
&mut Capstone::new()
@@ -4260,6 +4260,96 @@ fn test_arch_xcore_detail() {
42604260
);
42614261
}
42624262

4263+
#[cfg(feature = "arch_xtensa")]
4264+
#[test]
4265+
fn test_arch_xtensa() {
4266+
test_arch_mode_endian_insns(
4267+
&mut Capstone::new()
4268+
.xtensa()
4269+
.mode(xtensa::ArchMode::Default)
4270+
.build()
4271+
.unwrap(),
4272+
Arch::XTENSA,
4273+
Mode::Default,
4274+
None,
4275+
&[],
4276+
&[("abs", b"\x60\x51\x60"), ("add.n", b"\x1a\x23")],
4277+
);
4278+
}
4279+
4280+
#[cfg(feature = "arch_xtensa")]
4281+
#[test]
4282+
fn test_arch_xtensa_detail() {
4283+
use crate::arch::xtensa::{XtensaOpMem, XtensaOperand};
4284+
use capstone_sys::{cs_xtensa_op_mem, xtensa_reg::*};
4285+
4286+
test_arch_mode_endian_insns_detail(
4287+
&mut Capstone::new()
4288+
.xtensa()
4289+
.mode(xtensa::ArchMode::Default)
4290+
.build()
4291+
.unwrap(),
4292+
Arch::XTENSA,
4293+
Mode::Default,
4294+
None,
4295+
&[],
4296+
&[
4297+
// abs a5, a6
4298+
DII::new(
4299+
"abs",
4300+
b"\x60\x51\x60",
4301+
&[
4302+
XtensaOperand {
4303+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_A5 as RegIdInt)),
4304+
access: Some(RegAccessType::WriteOnly),
4305+
},
4306+
XtensaOperand {
4307+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_A6 as RegIdInt)),
4308+
access: Some(RegAccessType::ReadOnly),
4309+
},
4310+
],
4311+
),
4312+
// add.n a2, a3, a1
4313+
DII::new(
4314+
"add.n",
4315+
b"\x1a\x23",
4316+
&[
4317+
XtensaOperand {
4318+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_A2 as RegIdInt)),
4319+
access: Some(RegAccessType::WriteOnly),
4320+
},
4321+
XtensaOperand {
4322+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_A3 as RegIdInt)),
4323+
access: Some(RegAccessType::ReadOnly),
4324+
},
4325+
XtensaOperand {
4326+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_SP as RegIdInt)),
4327+
access: Some(RegAccessType::ReadOnly),
4328+
},
4329+
],
4330+
),
4331+
// l32i.n a1, a3, 8
4332+
DII::new(
4333+
"l32i.n",
4334+
b"\x18\x23",
4335+
&[
4336+
XtensaOperand {
4337+
op_type: xtensa::XtensaOperandType::Reg(RegId(XTENSA_REG_SP as RegIdInt)),
4338+
access: Some(RegAccessType::WriteOnly),
4339+
},
4340+
XtensaOperand {
4341+
op_type: xtensa::XtensaOperandType::Mem(XtensaOpMem(cs_xtensa_op_mem {
4342+
base: XTENSA_REG_A3 as u8,
4343+
disp: 8,
4344+
})),
4345+
access: Some(RegAccessType::ReadOnly),
4346+
},
4347+
],
4348+
),
4349+
],
4350+
);
4351+
}
4352+
42634353
#[cfg(feature = "arch_riscv")]
42644354
#[test]
42654355
fn test_arch_riscv() {

capstone-sys/build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ fn write_bindgen_bindings(
281281
.generate_comments(true)
282282
.layout_tests(false) // eliminate test failures on platforms with different pointer sizes
283283
.impl_debug(true)
284-
.constified_enum_module("cs_err|cs_group_type|cs_opt_value")
284+
.constified_enum_module("cs_err|cs_group_type|cs_opt_value|cs_xtensa_op_type")
285285
.bitfield_enum("cs_mode|cs_ac_type|arm_spsr_cspr_bits")
286286
.rustified_enum(".*")
287287
.array_pointers_in_arguments(true)

capstone-sys/pre_generated/capstone.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27866,23 +27866,22 @@ pub enum xtensa_insn_form {
2786627866
pub struct xtensa_suppl_info {
2786727867
pub form: xtensa_insn_form,
2786827868
}
27869-
#[repr(u32)]
27870-
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
27871-
pub enum cs_xtensa_op_type {
27869+
pub mod cs_xtensa_op_type {
27870+
pub type Type = libc::c_uint;
2787227871
#[doc = "< = (Uninitialized)."]
27873-
XTENSA_OP_INVALID = 0,
27872+
pub const XTENSA_OP_INVALID: Type = 0;
2787427873
#[doc = "< = (Register operand)."]
27875-
XTENSA_OP_REG = 1,
27874+
pub const XTENSA_OP_REG: Type = 1;
2787627875
#[doc = "< = (Immediate operand)."]
27877-
XTENSA_OP_IMM = 2,
27876+
pub const XTENSA_OP_IMM: Type = 2;
2787827877
#[doc = "< = (Memory operand)."]
27879-
XTENSA_OP_MEM = 128,
27878+
pub const XTENSA_OP_MEM: Type = 128;
2788027879
#[doc = "< = (Memory Register operand)."]
27881-
XTENSA_OP_MEM_REG = 129,
27880+
pub const XTENSA_OP_MEM_REG: Type = 129;
2788227881
#[doc = "< = (Memory Immediate operand)."]
27883-
XTENSA_OP_MEM_IMM = 130,
27882+
pub const XTENSA_OP_MEM_IMM: Type = 130;
2788427883
#[doc = "< = (L32R Target)"]
27885-
XTENSA_OP_L32R = 16,
27884+
pub const XTENSA_OP_L32R: Type = 16;
2788627885
}
2788727886
#[repr(C)]
2788827887
#[derive(Debug, Copy, Clone)]

0 commit comments

Comments
 (0)