1use core::convert::From;
4use core::{cmp, fmt, slice};
5
6use capstone_sys::{
7 cs_m68k, cs_m68k_op, cs_m68k_op__bindgen_ty_1, m68k_address_mode, m68k_cpu_size, m68k_fpu_size,
8 m68k_op_br_disp, m68k_op_mem, m68k_op_size, m68k_op_type, m68k_reg, m68k_size_type,
9};
10
11pub use capstone_sys::m68k_address_mode as M68kAddressMode;
13pub use capstone_sys::m68k_insn as M68kInsn;
14pub use capstone_sys::m68k_reg as M68kReg;
15
16pub use crate::arch::arch_builder::m68k::*;
17use crate::arch::DetailsArchInsn;
18use crate::Error;
19use crate::instruction::{RegId, RegIdInt};
20use crate::prelude::*;
21
22
23pub struct M68kInsnDetail<'a>(pub(crate) &'a cs_m68k);
25
26impl M68kInsnDetail<'_> {
27 pub fn op_size(&self) -> Option<M68kOpSize> {
29 M68kOpSize::new(&self.0.op_size)
30 }
31}
32
33define_cs_enum_wrapper_reverse!(
34 [
35 => M68kCpuSize = m68k_cpu_size,
37 ]
38 => None = M68K_CPU_SIZE_NONE;
40 => Byte = M68K_CPU_SIZE_BYTE;
42 => Word = M68K_CPU_SIZE_WORD;
44 => Long = M68K_CPU_SIZE_LONG;
46);
47
48define_cs_enum_wrapper_reverse!(
49 [
50 => M68kFpuSize = m68k_fpu_size,
53 ]
54 => None = M68K_FPU_SIZE_NONE;
56 => Single = M68K_FPU_SIZE_SINGLE;
58 => Double = M68K_FPU_SIZE_DOUBLE;
60 => Extended = M68K_FPU_SIZE_EXTENDED;
62);
63
64#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
66pub enum M68kOpSize {
67 Cpu(M68kCpuSize),
68 Fpu(M68kFpuSize),
69}
70
71#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
73pub struct M68kOpBranchDisplacement {
74 pub disp: i32,
76
77 pub disp_size: u8,
79}
80
81impl From<m68k_op_br_disp> for M68kOpBranchDisplacement {
82 fn from(other: m68k_op_br_disp) -> Self {
83 M68kOpBranchDisplacement {
84 disp: other.disp,
85 disp_size: other.disp_size,
86 }
87 }
88}
89
90impl M68kOpSize {
91 fn new(op: &m68k_op_size) -> Option<M68kOpSize> {
92 match op.type_ {
93 m68k_size_type::M68K_SIZE_TYPE_INVALID => None,
94 m68k_size_type::M68K_SIZE_TYPE_CPU => Some(M68kOpSize::Cpu(
95 unsafe { op.__bindgen_anon_1.cpu_size }.into(),
96 )),
97 m68k_size_type::M68K_SIZE_TYPE_FPU => Some(M68kOpSize::Fpu(
98 unsafe { op.__bindgen_anon_1.fpu_size }.into(),
99 )),
100 }
101 }
102}
103
104impl_PartialEq_repr_fields!(M68kInsnDetail<'a> [ 'a ];
105 op_size, operands
106);
107
108impl Default for M68kOperand {
109 fn default() -> Self {
110 M68kOperand::Invalid
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct M68kRegisterBits {
119 bits: u32,
123}
124
125const M68K_REGISTER_BITS_ALLOWED_MASK: u32 =
127 (1_u32 << ((m68k_reg::M68K_REG_FP7 as u8 - m68k_reg::M68K_REG_D0 as u8) + 1_u8)) - 1;
128
129impl M68kRegisterBits {
130 pub fn from_bitfield(bitfield: u32) -> CsResult<Self> {
134 if bitfield & !M68K_REGISTER_BITS_ALLOWED_MASK != 0 {
135 Err(Error::InvalidM68kBitfieldRegister)
136 } else {
137 Ok(M68kRegisterBits { bits: bitfield })
138 }
139 }
140
141 pub fn from_bitfield_infallible(bitfield: u32) -> Self {
145 M68kRegisterBits {
146 bits: bitfield & M68K_REGISTER_BITS_ALLOWED_MASK,
147 }
148 }
149
150 pub fn from_register_iter<T: Iterator<Item = R>, R: Into<M68kReg::Type>>(
153 reg_iter: T,
154 ) -> CsResult<Self> {
155 let mut bits: u32 = 0;
156 for reg in reg_iter {
157 bits |= 1 << M68kRegisterBits::m68k_reg_to_bit_idx(reg.into())?;
158 }
159 Ok(M68kRegisterBits { bits })
160 }
161
162 #[inline]
166 pub fn m68k_reg_to_bit_idx(reg: M68kReg::Type) -> CsResult<u8> {
167 use capstone_sys::m68k_reg::*;
168
169 if (M68K_REG_D0..=M68K_REG_FP7).contains(®) {
170 Ok((reg - M68K_REG_D0) as u8)
171 } else {
172 Err(Error::InvalidM68kBitfieldRegister)
173 }
174 }
175
176 #[inline]
178 pub fn as_bits(&self) -> u32 {
179 self.bits
180 }
181}
182
183#[derive(Clone, Debug, PartialEq)]
185pub enum M68kOperand {
186 Reg(RegId),
188
189 Imm(u32),
191
192 Mem(M68kOpMem),
194
195 FpSingle(f32),
197
198 FpDouble(f64),
200
201 RegBits(M68kRegisterBits),
203
204 RegPair(RegId, RegId),
206
207 Displacement(M68kOpBranchDisplacement),
209
210 Invalid,
212}
213
214impl M68kOperand {
215 fn new(cs_op: &cs_m68k_op) -> M68kOperand {
216 use self::m68k_op_type::*;
217 use self::M68kOperand::*;
218
219 let value: cs_m68k_op__bindgen_ty_1 = cs_op.__bindgen_anon_1;
220
221 match cs_op.type_ {
222 M68K_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
223 M68K_OP_IMM => Imm(unsafe { value.imm } as u32),
224 M68K_OP_MEM => Mem(M68kOpMem::new(cs_op)),
225 M68K_OP_FP_SINGLE => FpSingle(unsafe { value.simm }),
226 M68K_OP_FP_DOUBLE => FpDouble(unsafe { value.dimm }),
227 M68K_OP_REG_BITS => RegBits(M68kRegisterBits::from_bitfield_infallible(
228 cs_op.register_bits,
229 )),
230 M68K_OP_REG_PAIR => {
231 let reg_pair = unsafe { value.reg_pair };
232 RegPair(
233 RegId(reg_pair.reg_0 as RegIdInt),
234 RegId(reg_pair.reg_1 as RegIdInt),
235 )
236 }
237 M68K_OP_BR_DISP => Displacement(cs_op.br_disp.into()),
238 M68K_OP_INVALID => Invalid,
239 }
240 }
241}
242
243#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
246pub(crate) enum M68kOpMemExtraInfo {
247 None,
249
250 Reg(RegId),
252
253 Imm(u32),
255}
256
257impl M68kOpMemExtraInfo {
258 pub(crate) fn reg(&self) -> Option<RegId> {
260 if let M68kOpMemExtraInfo::Reg(reg) = self {
261 Some(*reg)
262 } else {
263 None
264 }
265 }
266
267 pub(crate) fn imm(&self) -> Option<u32> {
269 if let M68kOpMemExtraInfo::Imm(imm) = self {
270 Some(*imm)
271 } else {
272 None
273 }
274 }
275}
276
277#[derive(Debug, Clone)]
279pub struct M68kOpMem {
280 pub(crate) op_mem: m68k_op_mem,
281 pub(crate) address_mode: m68k_address_mode,
282
283 pub(crate) extra_info: M68kOpMemExtraInfo,
285}
286
287macro_rules! define_m68k_register_option_getter {
288 (
289 $( #[$enum_attr:meta] )*
290 => $field:ident
291 ) => {
292 $( #[$enum_attr] )*
293 pub fn $field(&self) -> Option<RegId> {
294 if self.op_mem.$field == M68kReg::M68K_REG_INVALID {
295 None
296 } else {
297 Some(RegId(self.op_mem.$field as RegIdInt))
298 }
299 }
300 }
301}
302
303macro_rules! define_m68k_getter {
304 (
305 $( #[$enum_attr:meta] )*
306 => $field:ident : $ret_type:ty
307 ) => {
308 $( #[$enum_attr] )*
309 pub fn $field(&self) -> $ret_type {
310 self.op_mem.$field
311 }
312 }
313}
314
315#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
317pub enum M68kIndexSize {
318 W,
319
320 L,
322}
323
324impl M68kOpMem {
325 pub fn new(op: &cs_m68k_op) -> Self {
327 use self::M68kAddressMode::*;
328
329 let address_mode = op.address_mode;
330 let value: cs_m68k_op__bindgen_ty_1 = op.__bindgen_anon_1;
331
332 let extra_info = match address_mode {
333 M68K_AM_REG_DIRECT_DATA
334 | M68K_AM_REG_DIRECT_ADDR
335 | M68K_AM_REGI_ADDR
336 | M68K_AM_REGI_ADDR_POST_INC
337 | M68K_AM_REGI_ADDR_PRE_DEC => {
338 M68kOpMemExtraInfo::Reg(RegId(unsafe { value.reg } as RegIdInt))
339 }
340
341 M68K_AM_ABSOLUTE_DATA_LONG | M68K_AM_ABSOLUTE_DATA_SHORT | M68K_AM_IMMEDIATE => {
343 M68kOpMemExtraInfo::Imm(unsafe { value.imm } as u32)
344 }
345
346 M68K_AM_PCI_INDEX_8_BIT_DISP
347 | M68K_AM_PCI_INDEX_BASE_DISP
348 | M68K_AM_AREGI_INDEX_BASE_DISP
349 | M68K_AM_BRANCH_DISPLACEMENT
350 | M68K_AM_NONE
351 | M68K_AM_REGI_ADDR_DISP
352 | M68K_AM_AREGI_INDEX_8_BIT_DISP
353 | M68K_AM_PC_MEMI_POST_INDEX
354 | M68K_AM_PC_MEMI_PRE_INDEX
355 | M68K_AM_MEMI_PRE_INDEX
356 | M68K_AM_MEMI_POST_INDEX
357 | M68K_AM_PCI_DISP => M68kOpMemExtraInfo::None,
358 };
359
360 M68kOpMem {
361 op_mem: op.mem,
362 address_mode,
363 extra_info,
364 }
365 }
366
367 define_m68k_register_option_getter!(
368 => base_reg
370 );
371
372 define_m68k_register_option_getter!(
373 => index_reg
375 );
376
377 define_m68k_register_option_getter!(
378 => in_base_reg
380 );
381
382 define_m68k_getter!(
383 => in_disp: u32
385 );
386
387 define_m68k_getter!(
388 => out_disp: u32
390 );
391
392 define_m68k_getter!(
393 => disp: i16
395 );
396
397 define_m68k_getter!(
398 => scale: u8
400 );
401
402 pub fn bitfield(&self) -> Option<(u8, u8)> {
404 if self.op_mem.bitfield == 0 {
405 None
406 } else {
407 Some((self.op_mem.width, self.op_mem.offset))
408 }
409 }
410
411 pub fn index_size(&self) -> M68kIndexSize {
412 if self.op_mem.index_size == 0 {
413 M68kIndexSize::W
414 } else {
415 M68kIndexSize::L
416 }
417 }
418
419 pub fn address_mode(&self) -> M68kAddressMode {
421 self.address_mode
422 }
423
424 pub(crate) fn extra_info(&self) -> M68kOpMemExtraInfo {
426 self.extra_info
427 }
428
429 pub fn reg(&self) -> Option<RegId> {
431 self.extra_info.reg()
432 }
433
434 pub fn imm(&self) -> Option<u32> {
436 self.extra_info.imm()
437 }
438}
439
440impl_PartialEq_repr_fields!(M68kOpMem;
441 base_reg, index_reg, in_base_reg, in_disp, out_disp, disp, scale, bitfield, index_size,
442 address_mode, extra_info
443);
444
445impl cmp::Eq for M68kOpMem {}
446
447impl From<&cs_m68k_op> for M68kOperand {
448 fn from(insn: &cs_m68k_op) -> M68kOperand {
449 M68kOperand::new(insn)
450 }
451}
452
453def_arch_details_struct!(
454 InsnDetail = M68kInsnDetail;
455 Operand = M68kOperand;
456 OperandIterator = M68kOperandIterator;
457 OperandIteratorLife = M68kOperandIterator<'a>;
458 [ pub struct M68kOperandIterator<'a>(slice::Iter<'a, cs_m68k_op>); ]
459 cs_arch_op = cs_m68k_op;
460 cs_arch = cs_m68k;
461);
462
463#[cfg(test)]
464mod test {
465 use super::*;
466 use capstone_sys::m68k_address_mode::*;
467 use capstone_sys::m68k_op_type::*;
468 use capstone_sys::m68k_reg::*;
469
470 const MEM_ZERO: m68k_op_mem = m68k_op_mem {
471 base_reg: M68K_REG_INVALID,
472 index_reg: M68K_REG_INVALID,
473 in_base_reg: M68K_REG_INVALID,
474 in_disp: 0,
475 out_disp: 0,
476 disp: 0,
477 scale: 0,
478 bitfield: 0,
479 width: 0,
480 offset: 0,
481 index_size: 0,
482 };
483
484 #[test]
485 fn test_m68k_op_from() {
486 let op_zero = cs_m68k_op {
487 __bindgen_anon_1: cs_m68k_op__bindgen_ty_1 { imm: 0 },
488 mem: MEM_ZERO,
489 br_disp: m68k_op_br_disp {
490 disp: 0,
491 disp_size: 0,
492 },
493 register_bits: 0,
494 type_: M68K_OP_IMM,
495 address_mode: M68K_AM_NONE,
496 };
497
498 let op_reg = cs_m68k_op {
500 __bindgen_anon_1: cs_m68k_op__bindgen_ty_1 { reg: M68K_REG_D7 },
501 type_: M68K_OP_REG,
502 ..op_zero
503 };
504 assert_eq!(
505 M68kOperand::new(&op_reg),
506 M68kOperand::Reg(RegId(M68K_REG_D7 as RegIdInt))
507 );
508
509 let op_imm = cs_m68k_op {
511 __bindgen_anon_1: cs_m68k_op__bindgen_ty_1 { imm: 42 },
512 type_: M68K_OP_IMM,
513 ..op_zero
514 };
515 assert_eq!(M68kOperand::new(&op_imm), M68kOperand::Imm(42));
516
517 let op_mem1 = m68k_op_mem {
519 base_reg: M68K_REG_A0,
520 index_reg: M68K_REG_D0,
521 index_size: 0, ..MEM_ZERO
523 };
524 let op_mem = cs_m68k_op {
525 mem: op_mem1,
526 address_mode: M68K_AM_MEMI_POST_INDEX,
527 type_: M68K_OP_MEM,
528 ..op_zero
529 };
530 let rust_op_mem = M68kOpMem {
531 op_mem: op_mem1,
532 address_mode: M68K_AM_MEMI_POST_INDEX,
533 extra_info: M68kOpMemExtraInfo::None,
534 };
535 assert_eq!(
536 M68kOperand::new(&op_mem),
537 M68kOperand::Mem(rust_op_mem.clone())
538 );
539 assert_eq!(rust_op_mem.base_reg(), Some(RegId(M68K_REG_A0 as RegIdInt)));
540 assert_eq!(
541 rust_op_mem.index_reg(),
542 Some(RegId(M68K_REG_D0 as RegIdInt))
543 );
544 assert_eq!(rust_op_mem.in_base_reg(), None);
545 assert_eq!(rust_op_mem.disp(), 0);
546 assert_eq!(rust_op_mem.scale(), 0);
547 assert_eq!(rust_op_mem.bitfield(), None);
548 assert_eq!(rust_op_mem.index_size(), M68kIndexSize::W);
549 assert_eq!(rust_op_mem.address_mode(), M68K_AM_MEMI_POST_INDEX);
550 }
551
552 #[test]
553 fn register_bits_mask() {
554 assert_eq!(
555 M68K_REGISTER_BITS_ALLOWED_MASK,
556 0b1111_1111_1111_1111_1111_1111
557 );
558 }
559
560 #[test]
561 fn register_bits_from_bitfield() {
562 assert!(M68kRegisterBits::from_bitfield(0xff).is_ok());
563 assert!(M68kRegisterBits::from_bitfield(0xff_00).is_ok());
564 assert!(M68kRegisterBits::from_bitfield(0xff_00_00).is_ok());
565 assert!(M68kRegisterBits::from_bitfield(0xf_ff_00_00).is_err());
566 }
567
568 #[test]
569 fn register_bits_from_iter() {
570 let empty: &[m68k_reg::Type] = &[];
571 assert_eq!(
572 M68kRegisterBits::from_register_iter(empty.iter().copied()),
573 Ok(M68kRegisterBits { bits: 0 })
574 );
575 assert_eq!(
576 M68kRegisterBits::from_register_iter([M68K_REG_D1].iter().copied()),
577 Ok(M68kRegisterBits { bits: 0b10 })
578 );
579 assert_eq!(
580 M68kRegisterBits::from_register_iter(
581 [M68K_REG_D1, M68K_REG_A2, M68K_REG_FP7].iter().copied()
582 ),
583 Ok(M68kRegisterBits {
584 bits: 0b1000_0000_0000_0100_0000_0010
585 })
586 );
587 }
588
589 #[test]
590 fn register_bits_as_bits() {
591 let mask = 0b00110011;
592 assert_eq!(
593 mask,
594 M68kRegisterBits::from_bitfield(mask).unwrap().as_bits()
595 );
596 }
597
598 #[test]
599 fn op_eq() {
600 use crate::arch::m68k::M68kOperand::*;
601 use crate::arch::m68k::M68kReg::*;
602 use crate::arch::m68k::*;
603 use capstone_sys::m68k_address_mode::*;
604
605 assert_ne!(
606 M68kOperand::RegBits(
607 M68kRegisterBits::from_register_iter(
608 [M68K_REG_D0, M68K_REG_D2, M68K_REG_A2, M68K_REG_A3]
609 .iter().copied()
610 )
611 .unwrap()
612 ),
613 M68kOperand::RegBits(
614 M68kRegisterBits::from_register_iter(
615 [M68K_REG_D0, M68K_REG_A2, M68K_REG_A3].iter().copied()
616 )
617 .unwrap()
618 )
619 );
620 assert_ne!(
621 Mem(M68kOpMem {
622 op_mem: MEM_ZERO,
623 address_mode: M68K_AM_REGI_ADDR_PRE_DEC,
624 extra_info: M68kOpMemExtraInfo::Reg(RegId(M68K_REG_A7 as RegIdInt)),
625 }),
626 Mem(M68kOpMem {
627 op_mem: MEM_ZERO,
628 address_mode: M68K_AM_REGI_ADDR_PRE_DEC,
629 extra_info: M68kOpMemExtraInfo::Reg(RegId(M68K_REG_A6 as RegIdInt)),
630 })
631 );
632 }
633
634 #[cfg(all(feature = "full", feature = "arch_m68k"))]
635 #[test]
636 fn extra_info() {
637 use alloc::vec::Vec;
638 use crate::instruction::*;
639 use crate::arch::DetailsArchInsn;
640
641 let cs = Capstone::new()
642 .m68k()
643 .mode(arch::m68k::ArchMode::M68k040)
644 .detail(true)
645 .build()
646 .expect("Failed to create Capstone");
647
648 let code_parts: &[&'static [u8]] = &[
649 b"\x4e\xb9\x00\x00\x00\x12",
651 ];
652 let code: Vec<u8> = code_parts
653 .iter()
654 .flat_map(|x| x.iter()).copied()
655 .collect();
656 let insns = cs.disasm_all(&code, 0x1000).expect("Failed to disasm");
657 let mut insns_iter = insns.iter();
658
659 let insn_jsr: &Insn = insns_iter.next().unwrap();
661 let detail = cs.insn_detail(insn_jsr).unwrap();
662 let _arch_detail = detail.arch_detail();
663 let arch_detail = _arch_detail.m68k().unwrap();
664 let mut ops = arch_detail.operands();
665 if let M68kOperand::Mem(mem) = ops.next().unwrap() {
666 assert_eq!(mem.imm(), Some(0x12));
667 } else {
668 panic!("Not expected type")
669 }
670 }
671}