capstone_git/arch/
arm.rs

1//! Contains arm-specific types
2
3use 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
25/// Contains ARM-specific details for an instruction
26pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);
27
28/// ARM shift amount
29#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
30pub enum ArmShift {
31    Invalid,
32
33    /// Arithmetic shift right (immediate)
34    Asr(u32),
35
36    /// Logical shift left (immediate)
37    Lsl(u32),
38
39    /// Logical shift right (immediate)
40    Lsr(u32),
41
42    /// Rotate right (immediate)
43    Ror(u32),
44
45    /// Rotate right with extend (immediate)
46    Rrx(u32),
47
48    /// Arithmetic shift right (register)
49    AsrReg(RegId),
50
51    /// Logical shift left (register)
52    LslReg(RegId),
53
54    /// Logical shift right (register)
55    LsrReg(RegId),
56
57    /// Rotate right (register)
58    RorReg(RegId),
59
60    /// Rotate right with extend (register)
61    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/// ARM operand
120#[derive(Clone, Debug, PartialEq)]
121pub struct ArmOperand {
122    /// Vector Index for some vector operands
123    pub vector_index: Option<u32>,
124
125    /// Whether operand is subtracted
126    pub subtracted: bool,
127
128    pub shift: ArmShift,
129
130    /// Operand type
131    pub op_type: ArmOperandType,
132
133    /// How is this operand accessed?
134    ///
135    /// NOTE: this field is always `None` if the "full" feataure is not enabled.
136    pub access: Option<AccessType>
137}
138
139/// ARM operand
140#[derive(Clone, Debug, PartialEq)]
141pub enum ArmOperandType {
142    /// Register
143    Reg(RegId),
144
145    /// Immediate
146    Imm(i32),
147
148    /// Memory
149    Mem(ArmOpMem),
150
151    /// Floating point
152    Fp(f64),
153
154    /// C-IMM
155    Cimm(i32),
156
157    /// P-IMM
158    Pimm(i32),
159
160    /// SETEND instruction endianness
161    Setend(ArmSetendType),
162
163    /// Sysreg
164    SysReg(RegId),
165
166    /// Invalid
167    Invalid,
168}
169
170/// ARM memory operand
171#[derive(Debug, Copy, Clone)]
172pub struct ArmOpMem(pub(crate) arm_op_mem);
173
174impl ArmInsnDetail<'_> {
175    /// Whether the instruction is a user mode
176    pub fn usermode(&self) -> bool {
177        self.0.usermode
178    }
179
180    /// Vector size
181    pub fn vector_size(&self) -> i32 {
182        self.0.vector_size as i32
183    }
184
185    /// Type of vector data
186    pub fn vector_data(&self) -> ArmVectorData {
187        self.0.vector_data
188    }
189
190    /// CPS mode for CPS instruction
191    pub fn cps_mode(&self) -> ArmCPSMode {
192        self.0.cps_mode
193    }
194
195    /// CPS flag for CPS instruction
196    pub fn cps_flag(&self) -> ArmCPSFlag {
197        self.0.cps_flag
198    }
199
200    /// Condition codes
201    pub fn cc(&self) -> ArmCC {
202        self.0.cc
203    }
204
205    /// Whether this insn updates flags
206    pub fn update_flags(&self) -> bool {
207        self.0.update_flags
208    }
209
210    /// Whether writeback is required
211    pub fn writeback(&self) -> bool {
212        self.0.writeback
213    }
214
215    /// Memory barrier
216    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    /// Base register
228    pub fn base(&self) -> RegId {
229        RegId(self.0.base as RegIdInt)
230    }
231
232    /// Index value
233    pub fn index(&self) -> RegId {
234        RegId(self.0.index as RegIdInt)
235    }
236
237    /// Scale for index register (can be 1, or -1)
238    pub fn scale(&self) -> i32 {
239        self.0.scale as i32
240    }
241
242    /// Disp value
243    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}