capstone_git/arch/
m68k.rs

1//! Contains m68k-specific types
2
3use 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
11// XXX todo(tmfink): create rusty versions
12pub 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
23/// Contains M68K-specific details for an instruction
24pub struct M68kInsnDetail<'a>(pub(crate) &'a cs_m68k);
25
26impl M68kInsnDetail<'_> {
27    /// size of data operand works on in bytes (.b, .w, .l, etc)
28    pub fn op_size(&self) -> Option<M68kOpSize> {
29        M68kOpSize::new(&self.0.op_size)
30    }
31}
32
33define_cs_enum_wrapper_reverse!(
34    [
35        /// Operation size of the CPU instructions
36        => M68kCpuSize = m68k_cpu_size,
37    ]
38    /// Unsized or unspecified
39    => None = M68K_CPU_SIZE_NONE;
40    /// 1 byte in size
41    => Byte = M68K_CPU_SIZE_BYTE;
42    /// 2 bytes in size
43    => Word = M68K_CPU_SIZE_WORD;
44    /// 4 bytes in size
45    => Long = M68K_CPU_SIZE_LONG;
46);
47
48define_cs_enum_wrapper_reverse!(
49    [
50        /// Operation size of the FPU instructions (notice that FPU instruction can also use CPU
51        /// sizes if needed)
52        => M68kFpuSize = m68k_fpu_size,
53    ]
54    /// Unsized or unspecified
55    => None = M68K_FPU_SIZE_NONE;
56    /// 1 byte in size
57    => Single = M68K_FPU_SIZE_SINGLE;
58    /// 2 bytes in size
59    => Double = M68K_FPU_SIZE_DOUBLE;
60    /// 4 bytes in size
61    => Extended = M68K_FPU_SIZE_EXTENDED;
62);
63
64/// Operation size of the current instruction (NOT the actually size of instruction)
65#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
66pub enum M68kOpSize {
67    Cpu(M68kCpuSize),
68    Fpu(M68kFpuSize),
69}
70
71/// Data when operand is a branch displacement
72#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
73pub struct M68kOpBranchDisplacement {
74    /// Displacement value
75    pub disp: i32,
76
77    /// Size from M68kOpBranchDisplacement
78    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/// Contains bitfield used with M68kOperand::RegBits
115///
116/// Contains register bits for movem etc. (always in d0-d7, a0-a7, fp0-fp7 order)
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118pub struct M68kRegisterBits {
119    /// Internal bitfield
120    ///
121    /// INVARIANT: must only have bits set up to fp7
122    bits: u32,
123}
124
125/// Allowed bits are 1; disallowed bits are 0
126const 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    /// Create from a bitfield where 0th bit is d0, 1th bit is d1, ...
131    ///
132    /// Returns an error if invalid bits are set.
133    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    /// Create from a bitfield where 0th bit is d0, 1th bit is d1, ...
142    ///
143    /// Invalid bits are ignored.
144    pub fn from_bitfield_infallible(bitfield: u32) -> Self {
145        M68kRegisterBits {
146            bits: bitfield & M68K_REGISTER_BITS_ALLOWED_MASK,
147        }
148    }
149
150    /// Create from iterator over registers: d0-d7, a0-a7, fp0-fp7
151    /// Invalid registers will cause an error
152    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    /// Maps an M68K register to a bitfield index
163    ///
164    /// Returns an error if the register is invalid
165    #[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(&reg) {
170            Ok((reg - M68K_REG_D0) as u8)
171        } else {
172            Err(Error::InvalidM68kBitfieldRegister)
173        }
174    }
175
176    /// Returns bitfield as integer
177    #[inline]
178    pub fn as_bits(&self) -> u32 {
179        self.bits
180    }
181}
182
183/// M68K operand type
184#[derive(Clone, Debug, PartialEq)]
185pub enum M68kOperand {
186    /// Register
187    Reg(RegId),
188
189    /// Immediate
190    Imm(u32),
191
192    /// Memory
193    Mem(M68kOpMem),
194
195    /// Single precision floating-point
196    FpSingle(f32),
197
198    /// Double precision floating-point
199    FpDouble(f64),
200
201    /// Register bits move
202    RegBits(M68kRegisterBits),
203
204    /// Register pair in the same op (upper 4 bits for first reg, lower for second)
205    RegPair(RegId, RegId),
206
207    /// Branch displacement
208    Displacement(M68kOpBranchDisplacement),
209
210    /// Invalid
211    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//todo(tmfink: handle all cases
244/// Extra info accompanying `M68kOpMem` that is not part of union in `m68k_op_mem`
245#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
246pub(crate) enum M68kOpMemExtraInfo {
247    /// No extra info
248    None,
249
250    /// Register
251    Reg(RegId),
252
253    /// Immediate
254    Imm(u32),
255}
256
257impl M68kOpMemExtraInfo {
258    /// Register (if it exists)
259    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    /// Immediate (if it exists)
268    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/// M68K memory operand
278#[derive(Debug, Clone)]
279pub struct M68kOpMem {
280    pub(crate) op_mem: m68k_op_mem,
281    pub(crate) address_mode: m68k_address_mode,
282
283    /// Register that is populated depending on address mode
284    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/// M68K index size
316#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
317pub enum M68kIndexSize {
318    W,
319
320    /// Long
321    L,
322}
323
324impl M68kOpMem {
325    /// Create a `M68kOpMem` from `&cs_m68k_op`, which depends on
326    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            // The M68K_AM_IMMEDIATE case cannot be floating point because type will not be op_mem
342            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 register
369        => base_reg
370    );
371
372    define_m68k_register_option_getter!(
373        /// index register
374        => index_reg
375    );
376
377    define_m68k_register_option_getter!(
378        /// indirect base register
379        => in_base_reg
380    );
381
382    define_m68k_getter!(
383        /// Indirect displacement
384        => in_disp: u32
385    );
386
387    define_m68k_getter!(
388        /// other displacement
389        => out_disp: u32
390    );
391
392    define_m68k_getter!(
393        /// displacement value
394        => disp: i16
395    );
396
397    define_m68k_getter!(
398        /// scale for index register
399        => scale: u8
400    );
401
402    /// Returns (width, offset)
403    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    /// M68K addressing mode for this op
420    pub fn address_mode(&self) -> M68kAddressMode {
421        self.address_mode
422    }
423
424    /// Extra info not included in mem type
425    pub(crate) fn extra_info(&self) -> M68kOpMemExtraInfo {
426        self.extra_info
427    }
428
429    /// Register value
430    pub fn reg(&self) -> Option<RegId> {
431        self.extra_info.reg()
432    }
433
434    /// Immediate value
435    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        // Reg
499        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        // Imm
510        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        // Mem
518        let op_mem1 = m68k_op_mem {
519            base_reg: M68K_REG_A0,
520            index_reg: M68K_REG_D0,
521            index_size: 0, // w
522            ..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            // jsr     $12.l
650            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        // jsr
660        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}