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 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}