1use core::convert::From;
4use core::convert::TryInto;
5use core::{cmp, fmt, slice};
6
7use capstone_sys::cs_x86_encoding;
8pub use capstone_sys::x86_avx_bcast as X86AvxBcast;
9pub use capstone_sys::x86_avx_cc as X86AvxCC;
10pub use capstone_sys::x86_avx_rm as X86AvxRm;
11pub use capstone_sys::x86_insn as X86Insn;
12pub use capstone_sys::x86_insn_group as X86InsnGroup;
13pub use capstone_sys::x86_prefix as X86Prefix;
14pub use capstone_sys::x86_reg as X86Reg;
15pub use capstone_sys::x86_sse_cc as X86SseCC;
16pub use capstone_sys::x86_xop_cc as X86XopCC;
17use capstone_sys::{
18 cs_ac_type, cs_x86, cs_x86_op, cs_x86_op__bindgen_ty_1, x86_op_mem, x86_op_type,
19};
20
21use super::InsnOffsetSpan;
22pub use crate::arch::arch_builder::x86::*;
23use crate::arch::DetailsArchInsn;
24use crate::instruction::{AccessType, RegId, RegIdInt};
25
26pub struct X86InsnDetail<'a>(pub(crate) &'a cs_x86);
28
29impl X86OperandType {
32 fn new(op_type: x86_op_type, value: cs_x86_op__bindgen_ty_1) -> X86OperandType {
33 use self::x86_op_type::*;
34 use self::X86OperandType::*;
35
36 match op_type {
37 X86_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
38 X86_OP_IMM => Imm(unsafe { value.imm }),
39 X86_OP_MEM => Mem(X86OpMem(unsafe { value.mem })),
40 X86_OP_INVALID => Invalid,
41 }
42 }
43}
44
45#[derive(Clone, Debug, PartialEq, Eq)]
47pub struct X86Operand {
48 pub size: u8,
50
51 pub access: Option<AccessType>,
55
56 pub avx_bcast: X86AvxBcast,
58
59 pub avx_zero_opmask: bool,
61
62 pub op_type: X86OperandType,
64}
65
66#[derive(Clone, Debug, PartialEq, Eq)]
68pub enum X86OperandType {
69 Reg(RegId),
71
72 Imm(i64),
74
75 Mem(X86OpMem),
77
78 Invalid,
80}
81
82#[derive(Debug, Copy, Clone)]
84pub struct X86OpMem(pub(crate) x86_op_mem);
85
86impl X86InsnDetail<'_> {
87 pub fn prefix(&self) -> &[u8; 4] {
100 &self.0.prefix
101 }
102
103 pub fn opcode(&self) -> &[u8; 4] {
107 &self.0.opcode
108 }
109
110 pub fn encoding(&self) -> X86Encoding {
112 self.0.encoding.into()
113 }
114
115 pub fn rex(&self) -> u8 {
117 self.0.rex
118 }
119
120 pub fn addr_size(&self) -> u8 {
122 self.0.addr_size
123 }
124
125 pub fn modrm(&self) -> u8 {
127 self.0.modrm
128 }
129
130 pub fn sib(&self) -> u8 {
132 self.0.sib
133 }
134
135 pub fn disp(&self) -> i64 {
137 self.0.disp
138 }
139
140 pub fn sib_index(&self) -> RegId {
142 RegId(self.0.sib_index as RegIdInt)
143 }
144
145 pub fn sib_scale(&self) -> i8 {
147 self.0.sib_scale
148 }
149
150 pub fn sib_base(&self) -> RegId {
152 RegId(self.0.sib_base as RegIdInt)
153 }
154
155 pub fn xop_cc(&self) -> X86XopCC {
157 self.0.xop_cc
158 }
159
160 pub fn sse_cc(&self) -> X86SseCC {
162 self.0.sse_cc
163 }
164
165 pub fn avx_cc(&self) -> X86AvxCC {
167 self.0.avx_cc
168 }
169
170 pub fn avx_sae(&self) -> bool {
172 self.0.avx_sae
173 }
174
175 pub fn avx_rm(&self) -> X86AvxRm {
177 self.0.avx_rm
178 }
179}
180
181impl_PartialEq_repr_fields!(X86InsnDetail<'a> [ 'a ];
182 prefix, opcode, rex, addr_size, modrm, sib, disp, sib_index, sib_scale, sib_base, sse_cc,
183 avx_cc, avx_sae, avx_rm, operands
184);
185
186impl X86OpMem {
187 pub fn segment(&self) -> RegId {
189 RegId(self.0.segment as RegIdInt)
190 }
191
192 pub fn base(&self) -> RegId {
194 RegId(self.0.base as RegIdInt)
195 }
196
197 pub fn index(&self) -> RegId {
199 RegId(self.0.index as RegIdInt)
200 }
201
202 pub fn scale(&self) -> i32 {
204 self.0.scale as i32
205 }
206
207 pub fn disp(&self) -> i64 {
209 self.0.disp
210 }
211}
212
213impl_PartialEq_repr_fields!(X86OpMem;
214 segment, base, index, scale, disp
215);
216
217impl cmp::Eq for X86OpMem {}
218
219impl Default for X86Operand {
220 fn default() -> Self {
221 X86Operand {
222 size: 0,
223 access: None,
224 avx_bcast: X86AvxBcast::X86_AVX_BCAST_INVALID,
225 avx_zero_opmask: false,
226 op_type: X86OperandType::Invalid,
227 }
228 }
229}
230
231impl From<&cs_x86_op> for X86Operand {
232 fn from(op: &cs_x86_op) -> X86Operand {
233 let op_type = X86OperandType::new(op.type_, op.__bindgen_anon_1);
234 X86Operand {
235 size: op.size,
236 access: cs_ac_type(op.access as _).try_into().ok(),
237 avx_bcast: op.avx_bcast,
238 avx_zero_opmask: op.avx_zero_opmask,
239 op_type,
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, PartialEq, Eq)]
246pub struct X86Encoding {
247 pub modrm_offset: u8,
248 pub disp: Option<InsnOffsetSpan>,
249 pub imm: Option<InsnOffsetSpan>,
250}
251
252impl From<cs_x86_encoding> for X86Encoding {
253 fn from(encoding: cs_x86_encoding) -> Self {
254 Self {
255 modrm_offset: encoding.modrm_offset,
256 disp: if encoding.disp_offset == 0 {
257 None
258 } else {
259 Some(InsnOffsetSpan {
260 offset: encoding.disp_offset,
261 size: encoding.disp_size,
262 })
263 },
264 imm: if encoding.imm_offset == 0 {
265 None
266 } else {
267 Some(InsnOffsetSpan {
268 offset: encoding.imm_offset,
269 size: encoding.imm_size,
270 })
271 },
272 }
273 }
274}
275
276def_arch_details_struct!(
277 InsnDetail = X86InsnDetail;
278 Operand = X86Operand;
279 OperandIterator = X86OperandIterator;
280 OperandIteratorLife = X86OperandIterator<'a>;
281 [ pub struct X86OperandIterator<'a>(slice::Iter<'a, cs_x86_op>); ]
282 cs_arch_op = cs_x86_op;
283 cs_arch = cs_x86;
284);
285
286#[cfg(test)]
287mod test {
288 use super::*;
289 use capstone_sys::*;
290
291 #[test]
292 fn test_x86_op_type() {
293 use super::x86_op_type::*;
294 use super::X86OperandType::*;
295
296 fn t(
297 op_type_value: (x86_op_type, cs_x86_op__bindgen_ty_1),
298 expected_op_type: X86OperandType,
299 ) {
300 let (op_type, op_value) = op_type_value;
301 let op_type = X86OperandType::new(op_type, op_value);
302 assert_eq!(expected_op_type, op_type);
303 }
304
305 t(
306 (X86_OP_INVALID, cs_x86_op__bindgen_ty_1 { reg: 0 }),
307 Invalid,
308 );
309 t(
310 (X86_OP_REG, cs_x86_op__bindgen_ty_1 { reg: 0 }),
311 Reg(RegId(0)),
312 );
313 }
314
315 #[test]
316 fn test_x86_op_eq() {
317 let a1 = X86Operand {
318 op_type: X86OperandType::Imm(0),
319 ..Default::default()
320 };
321 let a2 = X86Operand {
322 op_type: X86OperandType::Imm(-100),
323 ..Default::default()
324 };
325
326 assert_eq!(a1, a1.clone());
327 assert_ne!(a1, a2);
328 }
329
330 #[test]
331 fn test_x86_insn_eq() {
332 fn t_eq(a: &cs_x86, b: &cs_x86) {
333 assert_eq!(X86InsnDetail(a), X86InsnDetail(b))
334 }
335 fn t_ne(a: &cs_x86, b: &cs_x86) {
336 assert_ne!(X86InsnDetail(a), X86InsnDetail(b))
337 }
338
339 let a1 = cs_x86 {
340 prefix: [0, 0, 0, 0],
341 opcode: [0, 0, 0, 0],
342 rex: 0,
343 addr_size: 0,
344 modrm: 0,
345 sib: 0,
346 disp: 0,
347 sib_index: x86_reg::X86_REG_INVALID,
348 sib_scale: 0,
349 sib_base: x86_reg::X86_REG_INVALID,
350 sse_cc: x86_sse_cc::X86_SSE_CC_INVALID,
351 avx_cc: x86_avx_cc::X86_AVX_CC_INVALID,
352 avx_sae: false,
353 avx_rm: x86_avx_rm::X86_AVX_RM_INVALID,
354 op_count: 0,
355 __bindgen_anon_1: cs_x86__bindgen_ty_1 { eflags: 0 },
356 encoding: cs_x86_encoding {
357 modrm_offset: 0,
358 disp_offset: 0,
359 disp_size: 0,
360 imm_offset: 0,
361 imm_size: 0,
362 },
363 xop_cc: x86_xop_cc::X86_XOP_CC_INVALID,
364 operands: [cs_x86_op {
365 type_: x86_op_type::X86_OP_INVALID,
366 __bindgen_anon_1: cs_x86_op__bindgen_ty_1 {
367 reg: x86_reg::X86_REG_INVALID,
368 },
369 size: 0,
370 avx_bcast: x86_avx_bcast::X86_AVX_BCAST_INVALID,
371 avx_zero_opmask: false,
372 access: 0,
373 }; 8],
374 };
375 let mut a2 = a1;
376 a2.operands[1].type_ = x86_op_type::X86_OP_REG;
377 let a1_clone = cs_x86 { ..a1 };
378 let a3 = cs_x86 { rex: 1, ..a1 };
379 let op_count_differ = cs_x86 { op_count: 1, ..a1 };
380 let mut op1_differ = op_count_differ;
381 op1_differ.operands[0].avx_bcast = x86_avx_bcast::X86_AVX_BCAST_2;
382
383 t_eq(&a1, &a1);
384 t_eq(&a1, &a2);
385 t_eq(&a1, &a1_clone);
386 t_ne(&a1, &a3);
387 t_ne(&a1, &op_count_differ);
388 t_ne(&op_count_differ, &op1_differ);
389 }
390
391 #[test]
392 fn test_x86_insn_encoding() {
393 assert_eq!(
394 X86Encoding::from(cs_x86_encoding {
395 modrm_offset: 0,
396 disp_offset: 0,
397 disp_size: 0,
398 imm_offset: 0,
399 imm_size: 0,
400 }),
401 X86Encoding {
402 modrm_offset: 0,
403 disp: None,
404 imm: None
405 }
406 );
407
408 assert_eq!(
409 X86Encoding::from(cs_x86_encoding {
410 modrm_offset: 1,
411 disp_offset: 2,
412 disp_size: 3,
413 imm_offset: 4,
414 imm_size: 5,
415 }),
416 X86Encoding {
417 modrm_offset: 1,
418 disp: Some(InsnOffsetSpan { offset: 2, size: 3 }),
419 imm: Some(InsnOffsetSpan { offset: 4, size: 5 }),
420 }
421 );
422 }
423}