1use core::convert::{From, TryInto};
4use core::{cmp, fmt, slice};
5use core::ffi::c_uint;
6
7use capstone_sys::{
8 arm_op_mem, arm_op_type, arm_shifter, cs_ac_type, cs_arm, cs_arm_op, cs_arm_op__bindgen_ty_2};
9
10pub use crate::arch::arch_builder::arm::*;
11use crate::arch::DetailsArchInsn;
12use crate::instruction::{RegId, RegIdInt};
13use crate::AccessType;
14
15pub use capstone_sys::arm_insn_group as ArmInsnGroup;
16pub use capstone_sys::arm_insn as ArmInsn;
17pub use capstone_sys::arm_reg as ArmReg;
18pub use capstone_sys::arm_vectordata_type as ArmVectorData;
19pub use capstone_sys::arm_cpsmode_type as ArmCPSMode;
20pub use capstone_sys::arm_cpsflag_type as ArmCPSFlag;
21pub use capstone_sys::arm_cc as ArmCC;
22pub use capstone_sys::arm_mem_barrier as ArmMemBarrier;
23pub use capstone_sys::arm_setend_type as ArmSetendType;
24
25pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);
27
28#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
30pub enum ArmShift {
31 Invalid,
32
33 Asr(u32),
35
36 Lsl(u32),
38
39 Lsr(u32),
41
42 Ror(u32),
44
45 Rrx(u32),
47
48 AsrReg(RegId),
50
51 LslReg(RegId),
53
54 LsrReg(RegId),
56
57 RorReg(RegId),
59
60 RrxReg(RegId),
62}
63
64impl ArmShift {
65 fn new(type_: arm_shifter, value: c_uint) -> ArmShift {
66 use self::arm_shifter::*;
67 use self::ArmShift::*;
68
69 macro_rules! arm_shift_match {
70 (
71 imm = [ $( $imm_r_enum:ident = $imm_c_enum:ident, )* ]
72 reg = [ $( $reg_r_enum:ident = $reg_c_enum:ident, )* ]
73 ) => {
74 match type_ {
75 ARM_SFT_INVALID => Invalid,
76
77 $(
78 $imm_c_enum => $imm_r_enum(value as u32) ,
79 )*
80 $(
81 $reg_c_enum => $reg_r_enum(RegId(value as RegIdInt)) ,
82 )*
83 }
84 }
85 }
86
87 arm_shift_match!(
88 imm = [
89 Asr = ARM_SFT_ASR, Lsl = ARM_SFT_LSL, Lsr = ARM_SFT_LSR,
90 Ror = ARM_SFT_ROR, Rrx = ARM_SFT_RRX,
91 ]
92 reg = [
93 AsrReg = ARM_SFT_ASR_REG, LslReg = ARM_SFT_LSL_REG, LsrReg = ARM_SFT_LSR_REG,
94 RorReg = ARM_SFT_ROR_REG, RrxReg = ARM_SFT_RRX_REG,
95 ]
96 )
97 }
98}
99
100impl ArmOperandType {
101 fn new(op_type: arm_op_type, value: cs_arm_op__bindgen_ty_2) -> ArmOperandType {
102 use self::arm_op_type::*;
103 use self::ArmOperandType::*;
104
105 match op_type {
106 ARM_OP_INVALID => Invalid,
107 ARM_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
108 ARM_OP_IMM => Imm(unsafe { value.imm }),
109 ARM_OP_MEM => Mem(ArmOpMem(unsafe { value.mem })),
110 ARM_OP_FP => Fp(unsafe { value.fp }),
111 ARM_OP_CIMM => Cimm(unsafe { value.imm }),
112 ARM_OP_PIMM => Pimm(unsafe { value.imm }),
113 ARM_OP_SETEND => Setend(unsafe { value.setend }),
114 ARM_OP_SYSREG => SysReg(RegId(unsafe { value.reg } as RegIdInt)),
115 }
116 }
117}
118
119#[derive(Clone, Debug, PartialEq)]
121pub struct ArmOperand {
122 pub vector_index: Option<u32>,
124
125 pub subtracted: bool,
127
128 pub shift: ArmShift,
129
130 pub op_type: ArmOperandType,
132
133 pub access: Option<AccessType>
137}
138
139#[derive(Clone, Debug, PartialEq)]
141pub enum ArmOperandType {
142 Reg(RegId),
144
145 Imm(i32),
147
148 Mem(ArmOpMem),
150
151 Fp(f64),
153
154 Cimm(i32),
156
157 Pimm(i32),
159
160 Setend(ArmSetendType),
162
163 SysReg(RegId),
165
166 Invalid,
168}
169
170#[derive(Debug, Copy, Clone)]
172pub struct ArmOpMem(pub(crate) arm_op_mem);
173
174impl ArmInsnDetail<'_> {
175 pub fn usermode(&self) -> bool {
177 self.0.usermode
178 }
179
180 pub fn vector_size(&self) -> i32 {
182 self.0.vector_size as i32
183 }
184
185 pub fn vector_data(&self) -> ArmVectorData {
187 self.0.vector_data
188 }
189
190 pub fn cps_mode(&self) -> ArmCPSMode {
192 self.0.cps_mode
193 }
194
195 pub fn cps_flag(&self) -> ArmCPSFlag {
197 self.0.cps_flag
198 }
199
200 pub fn cc(&self) -> ArmCC {
202 self.0.cc
203 }
204
205 pub fn update_flags(&self) -> bool {
207 self.0.update_flags
208 }
209
210 pub fn writeback(&self) -> bool {
212 self.0.writeback
213 }
214
215 pub fn mem_barrier(&self) -> ArmMemBarrier {
217 self.0.mem_barrier
218 }
219}
220
221impl_PartialEq_repr_fields!(ArmInsnDetail<'a> [ 'a ];
222 usermode, vector_size, vector_data, cps_mode, cps_flag, cc, update_flags, writeback,
223 mem_barrier, operands
224);
225
226impl ArmOpMem {
227 pub fn base(&self) -> RegId {
229 RegId(self.0.base as RegIdInt)
230 }
231
232 pub fn index(&self) -> RegId {
234 RegId(self.0.index as RegIdInt)
235 }
236
237 pub fn scale(&self) -> i32 {
239 self.0.scale as i32
240 }
241
242 pub fn disp(&self) -> i32 {
244 self.0.disp as i32
245 }
246}
247
248impl_PartialEq_repr_fields!(ArmOpMem;
249 base, index, scale, disp
250);
251
252impl cmp::Eq for ArmOpMem {}
253
254impl Default for ArmOperand {
255 fn default() -> Self {
256 ArmOperand {
257 vector_index: None,
258 subtracted: false,
259 shift: ArmShift::Invalid,
260 op_type: ArmOperandType::Invalid,
261 access: None
262 }
263 }
264}
265
266impl From<&cs_arm_op> for ArmOperand {
267 fn from(op: &cs_arm_op) -> ArmOperand {
268 let shift = ArmShift::new(op.shift.type_, op.shift.value);
269 let op_type = ArmOperandType::new(op.type_, op.__bindgen_anon_1);
270 let vector_index = if op.vector_index >= 0 {
271 Some(op.vector_index as u32)
272 } else {
273 None
274 };
275 ArmOperand {
276 vector_index,
277 shift,
278 op_type,
279 subtracted: op.subtracted,
280 access: cs_ac_type(op.access as _).try_into().ok(),
281 }
282 }
283}
284
285def_arch_details_struct!(
286 InsnDetail = ArmInsnDetail;
287 Operand = ArmOperand;
288 OperandIterator = ArmOperandIterator;
289 OperandIteratorLife = ArmOperandIterator<'a>;
290 [ pub struct ArmOperandIterator<'a>(slice::Iter<'a, cs_arm_op>); ]
291 cs_arch_op = cs_arm_op;
292 cs_arch = cs_arm;
293);
294
295#[cfg(test)]
296mod test {
297 use super::*;
298 use capstone_sys::*;
299
300 #[test]
301 fn test_armshift() {
302 use super::arm_shifter::*;
303 use super::ArmShift::*;
304 use core::ffi::c_uint;
305
306 fn t(shift_type_value: (arm_shifter, c_uint), arm_shift: ArmShift) {
307 let (shift_type, value) = shift_type_value;
308 assert_eq!(arm_shift, ArmShift::new(shift_type, value));
309 }
310
311 t((ARM_SFT_INVALID, 0), Invalid);
312 t((ARM_SFT_ASR, 0), Asr(0));
313 t((ARM_SFT_ASR_REG, 42), AsrReg(RegId(42)));
314 t((ARM_SFT_RRX_REG, 42), RrxReg(RegId(42)));
315 }
316
317 #[test]
318 fn test_arm_op_type() {
319 use super::arm_op_type::*;
320 use super::ArmOperandType::*;
321
322 fn t(
323 op_type_value: (arm_op_type, cs_arm_op__bindgen_ty_2),
324 expected_op_type: ArmOperandType,
325 ) {
326 let (op_type, op_value) = op_type_value;
327 let op_type = ArmOperandType::new(op_type, op_value);
328 assert_eq!(expected_op_type, op_type);
329 }
330
331 t(
332 (ARM_OP_INVALID, cs_arm_op__bindgen_ty_2 { reg: 0 }),
333 Invalid,
334 );
335 t(
336 (ARM_OP_REG, cs_arm_op__bindgen_ty_2 { reg: 0 }),
337 Reg(RegId(0)),
338 );
339 }
340
341 #[test]
342 fn test_arm_insn_detail_eq() {
343 let a1 = cs_arm {
344 usermode: false,
345 vector_size: 0,
346 vector_data: arm_vectordata_type::ARM_VECTORDATA_INVALID,
347 cps_mode: arm_cpsmode_type::ARM_CPSMODE_INVALID,
348 cps_flag: arm_cpsflag_type::ARM_CPSFLAG_INVALID,
349 cc: arm_cc::ARM_CC_INVALID,
350 update_flags: false,
351 writeback: false,
352 post_index: false,
353 mem_barrier: arm_mem_barrier::ARM_MB_INVALID,
354 op_count: 0,
355 operands: [
356 cs_arm_op {
357 vector_index: 0,
358 shift: cs_arm_op__bindgen_ty_1 {
359 type_: arm_shifter::ARM_SFT_INVALID,
360 value: 0
361 },
362 type_: arm_op_type::ARM_OP_INVALID,
363 __bindgen_anon_1: cs_arm_op__bindgen_ty_2 { imm: 0 },
364 subtracted: false,
365 access: 0,
366 neon_lane: 0,
367 }
368 ; 36]
369 };
370 let a2 = cs_arm {
371 usermode: true,
372 ..a1
373 };
374 let a3 = cs_arm {
375 op_count: 20,
376 ..a1
377 };
378 let a4 = cs_arm {
379 op_count: 19,
380 ..a1
381 };
382 let a4_clone = a4;
383 assert_eq!(ArmInsnDetail(&a1), ArmInsnDetail(&a1));
384 assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a2));
385 assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a3));
386 assert_ne!(ArmInsnDetail(&a3), ArmInsnDetail(&a4));
387 assert_eq!(ArmInsnDetail(&a4), ArmInsnDetail(&a4_clone));
388 }
389}