idalib/
insn.rs

1use std::mem;
2
3use bitflags::bitflags;
4
5use crate::ffi::insn::insn_t;
6use crate::ffi::insn::op::*;
7use crate::ffi::util::{is_basic_block_end, is_call_insn, is_indirect_jump_insn, is_ret_insn};
8
9pub use crate::ffi::insn::{arm, mips, x86};
10
11use crate::Address;
12
13pub type Register = u16;
14pub type Phrase = u16;
15
16#[derive(Clone, Copy)]
17#[repr(transparent)]
18pub struct Insn {
19    inner: insn_t,
20}
21
22#[derive(Clone, Copy)]
23#[repr(transparent)]
24pub struct Operand {
25    inner: op_t,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
29#[repr(u8)]
30pub enum OperandType {
31    // Void -- we exclude it during creation
32    Reg = o_reg,
33    Mem = o_mem,
34    Phrase = o_phrase,
35    Displ = o_displ,
36    Imm = o_imm,
37    Far = o_far,
38    Near = o_near,
39    IdpSpec0 = o_idpspec0,
40    IdpSpec1 = o_idpspec1,
41    IdpSpec2 = o_idpspec2,
42    IdpSpec3 = o_idpspec3,
43    IdpSpec4 = o_idpspec4,
44    IdpSpec5 = o_idpspec5,
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
48#[repr(u8)]
49pub enum OperandDataType {
50    Byte = dt_byte as _,
51    Word = dt_word as _,
52    DWord = dt_dword as _,
53    Float = dt_float as _,
54    Double = dt_double as _,
55    TByte = dt_tbyte as _,
56    PackReal = dt_packreal as _,
57    QWord = dt_qword as _,
58    Byte16 = dt_byte16 as _,
59    Code = dt_code as _,
60    Void = dt_void as _,
61    FWord = dt_fword as _,
62    Bitfield = dt_bitfild as _,
63    String = dt_string as _,
64    Unicode = dt_unicode as _,
65    LongDouble = dt_ldbl as _,
66    Byte32 = dt_byte32 as _,
67    Byte64 = dt_byte64 as _,
68    Half = dt_half as _,
69}
70
71bitflags! {
72    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73    pub struct OperandFlags: u8 {
74        const NO_BASE_DISP = OF_NO_BASE_DISP as _;
75        const OUTER_DISP = OF_OUTER_DISP as _;
76        const NUMBER = OF_NUMBER as _;
77        const SHOW = OF_SHOW as _;
78    }
79}
80
81bitflags! {
82    #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
83    pub struct IsReturnFlags: u8 {
84        const EXTENDED = IRI_EXTENDED as _;
85        const RET_LITERALLY = IRI_RET_LITERALLY as _;
86        const SKIP_RETTARGET = IRI_SKIP_RETTARGET as _;
87        const STRICT = IRI_STRICT as _;
88    }
89}
90
91pub type InsnType = u16;
92
93impl Insn {
94    pub(crate) fn from_repr(inner: insn_t) -> Self {
95        Self { inner }
96    }
97
98    pub fn address(&self) -> Address {
99        self.inner.ea
100    }
101
102    pub fn itype(&self) -> InsnType {
103        self.inner.itype as _
104    }
105
106    pub fn operand(&self, n: usize) -> Option<Operand> {
107        let op = self.inner.ops.get(n)?;
108
109        if op.type_ != o_void {
110            Some(Operand { inner: *op })
111        } else {
112            None
113        }
114    }
115
116    pub fn operand_count(&self) -> usize {
117        self.inner
118            .ops
119            .iter()
120            .position(|op| op.type_ == o_void)
121            .unwrap_or(self.inner.ops.len())
122    }
123
124    pub fn len(&self) -> usize {
125        self.inner.size as _
126    }
127
128    pub fn is_empty(&self) -> bool {
129        self.len() == 0
130    }
131
132    pub fn is_basic_block_end(&self, call_stops_block: bool) -> bool {
133        unsafe { is_basic_block_end(&self.inner, call_stops_block) }
134    }
135
136    pub fn is_call(&self) -> bool {
137        unsafe { is_call_insn(&self.inner) }
138    }
139
140    pub fn is_indirect_jump(&self) -> bool {
141        unsafe { is_indirect_jump_insn(&self.inner) }
142    }
143
144    pub fn is_ret(&self) -> bool {
145        self.is_ret_with(IsReturnFlags::STRICT)
146    }
147
148    pub fn is_ret_with(&self, iri: IsReturnFlags) -> bool {
149        unsafe { is_ret_insn(&self.inner, iri.bits()) }
150    }
151}
152
153impl Operand {
154    pub fn flags(&self) -> OperandFlags {
155        OperandFlags::from_bits_retain(self.inner.flags)
156    }
157
158    pub fn offb(&self) -> i8 {
159        self.inner.offb
160    }
161
162    pub fn offo(&self) -> i8 {
163        self.inner.offo
164    }
165
166    pub fn n(&self) -> usize {
167        self.inner.n as _
168    }
169
170    pub fn number(&self) -> usize {
171        self.n()
172    }
173
174    pub fn type_(&self) -> OperandType {
175        unsafe { mem::transmute(self.inner.type_) }
176    }
177
178    pub fn dtype(&self) -> OperandDataType {
179        unsafe { mem::transmute(self.inner.dtype) }
180    }
181
182    pub fn reg(&self) -> Option<Register> {
183        if self.is_processor_specific() || self.type_() == OperandType::Reg {
184            Some(unsafe { self.inner.__bindgen_anon_1.reg })
185        } else {
186            None
187        }
188    }
189
190    pub fn register(&self) -> Option<Register> {
191        self.reg()
192    }
193
194    pub fn phrase(&self) -> Option<Phrase> {
195        if self.is_processor_specific()
196            || matches!(self.type_(), OperandType::Phrase | OperandType::Displ)
197        {
198            Some(unsafe { self.inner.__bindgen_anon_1.phrase })
199        } else {
200            None
201        }
202    }
203
204    pub fn value(&self) -> Option<u64> {
205        if self.is_processor_specific() || self.type_() == OperandType::Imm {
206            Some(unsafe { self.inner.__bindgen_anon_2.value })
207        } else {
208            None
209        }
210    }
211
212    pub fn outer_displacement(&self) -> Option<u64> {
213        if self.flags().contains(OperandFlags::OUTER_DISP) {
214            Some(unsafe { self.inner.__bindgen_anon_2.value })
215        } else {
216            None
217        }
218    }
219
220    pub fn address(&self) -> Option<Address> {
221        self.addr()
222    }
223
224    pub fn addr(&self) -> Option<Address> {
225        if self.is_processor_specific()
226            || matches!(
227                self.type_(),
228                OperandType::Mem | OperandType::Displ | OperandType::Far | OperandType::Near
229            )
230        {
231            Some(unsafe { self.inner.__bindgen_anon_3.addr })
232        } else {
233            None
234        }
235    }
236
237    pub fn processor_specific(&self) -> Option<u64> {
238        if self.is_processor_specific() {
239            Some(unsafe { self.inner.__bindgen_anon_4.specval })
240        } else {
241            None
242        }
243    }
244
245    pub fn processor_specific_low(&self) -> Option<u16> {
246        if self.is_processor_specific() {
247            Some(unsafe { self.inner.__bindgen_anon_4.specval_shorts.low })
248        } else {
249            None
250        }
251    }
252
253    pub fn processor_specific_high(&self) -> Option<u16> {
254        if self.is_processor_specific() {
255            Some(unsafe { self.inner.__bindgen_anon_4.specval_shorts.high })
256        } else {
257            None
258        }
259    }
260
261    pub fn processor_specific_flag1(&self) -> Option<i8> {
262        if self.is_processor_specific() {
263            Some(self.inner.specflag1)
264        } else {
265            None
266        }
267    }
268
269    pub fn processor_specific_flag2(&self) -> Option<i8> {
270        if self.is_processor_specific() {
271            Some(self.inner.specflag2)
272        } else {
273            None
274        }
275    }
276
277    pub fn processor_specific_flag3(&self) -> Option<i8> {
278        if self.is_processor_specific() {
279            Some(self.inner.specflag3)
280        } else {
281            None
282        }
283    }
284
285    pub fn processor_specific_flag4(&self) -> Option<i8> {
286        if self.is_processor_specific() {
287            Some(self.inner.specflag4)
288        } else {
289            None
290        }
291    }
292
293    pub fn is_processor_specific(&self) -> bool {
294        matches!(
295            self.type_(),
296            OperandType::IdpSpec0
297                | OperandType::IdpSpec1
298                | OperandType::IdpSpec2
299                | OperandType::IdpSpec3
300                | OperandType::IdpSpec4
301                | OperandType::IdpSpec5
302        )
303    }
304}