capstone_git/arch/
mod.rs

1//! Contains architecture-specific types and modules
2
3// We use explicit casts from c_int (and such) so the code compiles on platforms with different
4// integer widths
5#![allow(clippy::unnecessary_cast)]
6
7use alloc::vec::Vec;
8use core::fmt::Debug;
9use core::marker::PhantomData;
10
11use crate::capstone::Capstone;
12use crate::constants::Endian;
13use crate::error::CsResult;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16pub struct InsnOffsetSpan {
17    pub offset: u8,
18    pub size: u8,
19}
20
21macro_rules! define_subset_enum {
22    ( [
23        $subset_enum:ident = $base_enum:ident
24      ]
25      $( $variant:ident, )*
26    ) => {
27        #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
28        pub enum $subset_enum {
29            $(
30                $variant,
31            )*
32        }
33
34        impl From<$subset_enum> for $base_enum {
35            fn from(other: $subset_enum) -> $base_enum {
36                match other {
37                    $(
38                        $subset_enum::$variant => $base_enum::$variant,
39                    )*
40                }
41            }
42        }
43    };
44}
45
46/// Define arch builders
47macro_rules! define_arch_builder {
48    // ExtraMode rules
49    ( @extra_modes () ) => {};
50    ( @extra_modes ( $( $extra_mode:ident, )+ ) ) => {
51        impl super::BuildsCapstoneExtraMode<ArchMode, ArchExtraMode> for ArchCapstoneBuilder {
52            fn extra_mode<T: Iterator<Item=ArchExtraMode>>(mut self, extra_mode: T) -> Self {
53                self.extra_mode.clear();
54                self.extra_mode.extend(extra_mode);
55                self
56            }
57        }
58    };
59
60    // Syntax rules
61    ( @syntax () ) => {};
62    ( @syntax ( $( $syntax:ident, )+ ) ) => {
63        impl super::BuildsCapstoneSyntax<ArchMode, ArchSyntax> for ArchCapstoneBuilder {
64            fn syntax(mut self, syntax: ArchSyntax) -> Self {
65                self.syntax = Some(syntax);
66                self
67            }
68        }
69    };
70
71    // Endian rules
72    ( @endian ( false) ) => {};
73    ( @endian ( true ) ) => {
74        impl super::BuildsCapstoneEndian<ArchMode> for ArchCapstoneBuilder {
75            fn endian(mut self, endian: Endian) -> Self {
76                self.endian = Some(endian);
77                self
78            }
79        }
80    };
81
82    // Entrance rule
83    (
84        $( [
85            ( $arch:ident, $arch_variant:ident, $feature:literal )
86            ( mode: $( $mode:ident, )+ )
87            ( extra_modes: $( $extra_mode:ident, )* )
88            ( syntax: $( $syntax:ident, )* )
89            ( both_endian: $( $endian:ident )* )
90        ] )+
91    ) => {
92        // We put builders in `arch::arch_builder::$ARCH` so we can put manual arch-specific code
93        // in `arch::$ARCH`. The contents of each module is imported from `arch::$ARCH`.
94
95        $(
96            /// Architecture-specific build code
97            #[cfg(feature = $feature)]
98            pub mod $arch {
99                use alloc::vec::Vec;
100
101                use crate::capstone::Capstone;
102                use crate::constants::{Arch, Endian, ExtraMode, Mode, Syntax};
103                use crate::error::{CsResult, Error};
104
105                define_arch_builder!( @syntax ( $( $syntax, )* ) );
106                define_arch_builder!( @endian ( $( $endian )* ) );
107                define_arch_builder!( @extra_modes ( $( $extra_mode, )* ) );
108
109                define_subset_enum!(
110                    [ ArchMode = Mode ]
111                    $( $mode, )*
112                );
113
114                define_subset_enum!(
115                    [ ArchExtraMode = ExtraMode ]
116                    $( $extra_mode, )*
117                );
118
119                define_subset_enum!(
120                    [ ArchSyntax = Syntax ]
121                    $( $syntax, )*
122                );
123
124                #[derive(Clone)]
125                pub struct ArchCapstoneBuilder {
126                    pub(crate) mode: Option<ArchMode>,
127                    pub(crate) is_detail: bool,
128                    pub(crate) extra_mode: Vec<ArchExtraMode>,
129                    pub(crate) syntax: Option<ArchSyntax>,
130                    pub(crate) endian: Option<Endian>,
131                }
132
133                impl super::BuildsCapstone<ArchMode> for ArchCapstoneBuilder {
134                    fn mode(mut self, mode: ArchMode) -> Self {
135                        self.mode = Some(mode);
136                        self
137                    }
138
139                    fn detail(mut self, enable_detail: bool) -> Self {
140                        self.is_detail = enable_detail;
141                        self
142                    }
143
144                    fn build(self) -> CsResult<Capstone> {
145                        let mode = match self.mode {
146                            Some(mode) => mode,
147                            None => {
148                                let msg: &'static str = concat!(
149                                    "Must specify mode for ",
150                                    stringify!($arch),
151                                    "::ArchCapstoneBuilder with `mode()` method",
152                                );
153                                return Err(Error::CustomError(msg));
154                            }
155                        };
156                        let extra_mode = self.extra_mode.iter().map(|x| ExtraMode::from(*x));
157                        let mut capstone = Capstone::new_raw(Arch::$arch_variant,
158                                                             mode.into(),
159                                                             extra_mode,
160                                                             self.endian)?;
161
162                        if let Some(syntax) = self.syntax {
163                            capstone.set_syntax(Syntax::from(syntax))?;
164                        }
165                        if self.is_detail {
166                            capstone.set_detail(self.is_detail)?;
167                        }
168
169                        Ok(capstone)
170                    }
171                }
172
173                impl Default for ArchCapstoneBuilder {
174                    fn default() -> Self {
175                        ArchCapstoneBuilder {
176                            mode: None,
177                            is_detail: false,
178                            extra_mode: vec![],
179                            endian: None,
180                            syntax: None,
181                        }
182                    }
183                }
184            }
185        )+
186
187        impl CapstoneBuilder {
188            $(
189                #[cfg(feature = $feature)]
190                pub fn $arch(self) -> $arch::ArchCapstoneBuilder {
191                    Default::default()
192                }
193            )*
194        }
195    }
196}
197
198/// Base X macro with arch info
199///
200/// Notes:
201/// - Even though [Capstone's documentation](https://www.capstone-engine.org/lang_c.html)
202///   classifies V9 as an extra mode, we classify it as a Mode since the only other mode is Default
203///   (which is treated as Big endian)
204macro_rules! arch_info_base {
205    ($x_macro:ident) => {
206        $x_macro!(
207            [
208                ( arm, ARM, "arch_arm" )
209                ( mode:
210                    Arm,
211                    Thumb,
212                    )
213                ( extra_modes:
214                    MClass,
215                    V8,
216                    )
217                ( syntax:
218                    NoRegName,
219                    )
220                ( both_endian: true )
221            ]
222            [
223                ( arm64, ARM64, "arch_arm64" )
224                ( mode:
225                    Arm,
226                    )
227                ( extra_modes: )
228                ( syntax: )
229                ( both_endian: true )
230            ]
231            [
232                ( evm, EVM, "arch_evm" )
233                ( mode:
234                    Default,
235                    )
236                ( extra_modes: )
237                ( syntax: )
238                ( both_endian: false )
239            ]
240            [
241                ( m680x, M680X, "arch_m680x" )
242                ( mode:
243                    M680x6301,
244                    M680x6309,
245                    M680x6800,
246                    M680x6801,
247                    M680x6805,
248                    M680x6808,
249                    M680x6809,
250                    M680x6811,
251                    M680xCpu12,
252                    M680xHcs08,
253                    )
254                ( extra_modes: )
255                ( syntax: )
256                ( both_endian: false )
257            ]
258            [
259                ( m68k, M68K, "arch_m68k" )
260                ( mode:
261                    M68k000,
262                    M68k010,
263                    M68k020,
264                    M68k030,
265                    M68k040,
266                    )
267                ( extra_modes: )
268                ( syntax: )
269                ( both_endian: false )
270            ]
271            [
272                ( mips, MIPS, "arch_mips" )
273                ( mode:
274                    Mips32,
275                    Mips64,
276                    Mips2,
277                    Mips3,
278                    Mips32R6,
279                    )
280                ( extra_modes:
281                    Micro,
282                    )
283                ( syntax: )
284                ( both_endian: true )
285            ]
286            [
287                ( mos65xx, MOS65XX, "arch_mos65xx" )
288                ( mode:
289                    Mos65xx6502,
290                    Mos65xx65c02,
291                    Mos65xxW65c02,
292                    Mos65xx65816,
293                    Mos65xx65816LongM,
294                    Mos65xx65816LongX,
295                    Mos65xx65816LongMx,
296                    )
297                ( extra_modes: )
298                ( syntax: )
299                ( both_endian: false )
300            ]
301            [
302                ( ppc, PPC, "arch_powerpc" )
303                ( mode:
304                    Mode32,
305                    Mode64,
306                    Qpx,
307                    )
308                ( extra_modes: )
309                ( syntax:
310                    NoRegName,
311                    )
312                ( both_endian: true )
313            ]
314            [
315                ( riscv, RISCV, "arch_riscv" )
316                ( mode:
317                    RiscV32,
318                    RiscV64,
319                    )
320                ( extra_modes:
321                    RiscVC,
322                    )
323                ( syntax: )
324                ( both_endian: true )
325            ]
326            [
327                ( sh, SH, "arch_sh" )
328                ( mode:
329                    Sh2,
330                    Sh2a,
331                    Sh3,
332                    Sh4,
333                    Sh4a,
334                    ShFpu,
335                    ShDsp,
336                    )
337                ( extra_modes: )
338                ( syntax: )
339                ( both_endian: false )
340            ]
341            [
342                ( sparc, SPARC, "arch_sparc" )
343                ( mode:
344                    Default,
345                    V9,
346                    )
347                ( extra_modes: )
348                ( syntax: )
349                ( both_endian: false )
350            ]
351            [
352                ( sysz, SYSZ, "arch_sysz" )
353                ( mode:
354                    Default,
355                    )
356                ( extra_modes: )
357                ( syntax: )
358                ( both_endian: false )
359            ]
360            [
361                ( tms320c64x, TMS320C64X, "arch_tms320c64x" )
362                ( mode:
363                    Default,
364                    )
365                ( extra_modes: )
366                ( syntax: )
367                ( both_endian: true )
368            ]
369            [
370                ( tricore, TRICORE, "arch_tricore" )
371                ( mode:
372                    TriCore110,
373                    TriCore120,
374                    TriCore130,
375                    TriCore131,
376                    TriCore160,
377                    TriCore161,
378                    TriCore162,
379                    )
380                ( extra_modes: )
381                ( syntax: )
382                ( both_endian: true )
383            ]
384            [
385                ( x86, X86, "arch_x86" )
386                ( mode:
387                    Mode16,
388                    Mode32,
389                    Mode64,
390                    )
391                ( extra_modes: )
392                ( syntax:
393                    Intel,
394                    Att,
395                    Masm,
396                    )
397                ( both_endian: false )
398            ]
399            [
400                ( xcore, XCORE, "arch_xcore" )
401                ( mode:
402                    Default,
403                    )
404                ( extra_modes: )
405                ( syntax: )
406                ( both_endian: false  )
407            ]
408            [
409                ( bpf, BPF, "arch_bpf" )
410                ( mode:
411                    Cbpf,
412                    Ebpf,
413                )
414                ( extra_modes: )
415                ( syntax: )
416                ( both_endian: true  )
417            ]
418        );
419    };
420}
421
422/// Builds a `Capstone` struct
423pub trait BuildsCapstone<ArchMode> {
424    /// Set the disassembly mode
425    fn mode(self, mode: ArchMode) -> Self;
426
427    /// Enable detailed output
428    fn detail(self, enable_detail: bool) -> Self;
429
430    /// Get final `Capstone`
431    fn build(self) -> CsResult<Capstone>;
432}
433
434/// Implies that a `CapstoneBuilder` architecture has extra modes
435pub trait BuildsCapstoneExtraMode<ArchMode, ArchExtraMode>: BuildsCapstone<ArchMode> {
436    /// Set architecture endianness
437    fn extra_mode<T: Iterator<Item = ArchExtraMode>>(self, extra_mode: T) -> Self;
438}
439
440/// Implies that a `CapstoneBuilder` has different syntax options
441pub trait BuildsCapstoneSyntax<ArchMode, ArchSyntax>: BuildsCapstone<ArchMode> {
442    /// Set the disassembly syntax
443    fn syntax(self, syntax: ArchSyntax) -> Self;
444}
445
446/// Implies that a `CapstoneBuilder` architecture has a configurable endianness
447pub trait BuildsCapstoneEndian<ArchMode>: BuildsCapstone<ArchMode> {
448    /// Set architecture endianness
449    fn endian(self, endian: Endian) -> Self;
450}
451
452/// Contains builder-pattern implementations
453pub(crate) mod arch_builder {
454    use super::*;
455
456    arch_info_base!(define_arch_builder);
457}
458
459/// Builds `Capstone` object
460#[derive(Debug)]
461pub struct CapstoneBuilder(
462    /// Hidden field to prevent users from instantiating `CapstoneBuilder`
463    PhantomData<()>,
464);
465
466impl CapstoneBuilder {
467    /// Create a `CapstoneBuilder`
468    pub(crate) fn new() -> Self {
469        CapstoneBuilder(PhantomData)
470    }
471}
472
473/// Provides architecture-specific details about an instruction
474pub trait DetailsArchInsn: PartialEq + Debug {
475    type Operand: Into<ArchOperand> + Default + Clone + Debug + PartialEq;
476    type OperandIterator: Iterator<Item = Self::Operand>;
477
478    fn operands(&self) -> Self::OperandIterator;
479}
480
481/// Define PartialEq for a type given representation getter methods
482macro_rules! impl_PartialEq_repr_fields {
483    // With generic parameters
484    (
485        $name:ty [ $( $lifetime:tt ),* ];
486        $( $field:ident),*
487    ) => {
488        impl<$( $lifetime ),*> ::core::cmp::PartialEq for $name {
489            fn eq(&self, other: &Self) -> bool {
490                $(
491                    if self.$field() != other.$field() {
492                        return false;
493                    }
494                )*
495                true
496            }
497        }
498    };
499
500    // No generic parameters
501    (
502        $name:ty;
503        $( $field:ident),*
504    ) => {
505        impl_PartialEq_repr_fields!(
506            $name [];
507            $( $field),*
508        );
509    };
510}
511
512/// Base macro for defining arch details
513macro_rules! detail_arch_base {
514    ($x_macro:ident) => {
515        $x_macro!(
516            [
517                detail = ArmDetail,
518                insn_detail = ArmInsnDetail<'a>,
519                op = ArmOperand,
520                feature = "arch_arm",
521                /// Returns the ARM details, if any
522                => arch_name = arm,
523            ]
524            [
525                detail = Arm64Detail,
526                insn_detail = Arm64InsnDetail<'a>,
527                op = Arm64Operand,
528                feature = "arch_arm64",
529                /// Returns the ARM64 details, if any
530                => arch_name = arm64,
531            ]
532            [
533                detail = EvmDetail,
534                insn_detail = EvmInsnDetail<'a>,
535                op = EvmOperand,
536                feature = "arch_evm",
537                /// Returns the EVM details, if any
538                => arch_name = evm,
539            ]
540            [
541                detail = M680xDetail,
542                insn_detail = M680xInsnDetail<'a>,
543                op = M680xOperand,
544                feature = "arch_m680x",
545                /// Returns the M680X details, if any
546                => arch_name = m680x,
547            ]
548            [
549                detail = M68kDetail,
550                insn_detail = M68kInsnDetail<'a>,
551                op = M68kOperand,
552                feature = "arch_m68k",
553                /// Returns the M68K details, if any
554                => arch_name = m68k,
555            ]
556            [
557                detail = MipsDetail,
558                insn_detail = MipsInsnDetail<'a>,
559                op = MipsOperand,
560                feature = "arch_mips",
561                /// Returns the MIPS details, if any
562                => arch_name = mips,
563            ]
564            [
565                detail = Mos65xxDetail,
566                insn_detail = Mos65xxInsnDetail<'a>,
567                op = Mos65xxOperand,
568                feature = "arch_mos65xx",
569                /// Returns the Mos65xx details, if any
570                => arch_name = mos65xx,
571            ]
572            [
573                detail = PpcDetail,
574                insn_detail = PpcInsnDetail<'a>,
575                op = PpcOperand,
576                feature = "arch_powerpc",
577                /// Returns the PPC details, if any
578                => arch_name = ppc,
579            ]
580            [
581                detail = RiscVDetail,
582                insn_detail = RiscVInsnDetail<'a>,
583                op = RiscVOperand,
584                feature = "arch_riscv",
585                /// Returns the RISCV details, if any
586                => arch_name = riscv,
587            ]
588            [
589                detail = ShDetail,
590                insn_detail = ShInsnDetail<'a>,
591                op = ShOperand,
592                feature = "arch_sh",
593                /// Returns the SH details, if any
594                => arch_name = sh,
595            ]
596            [
597                detail = SparcDetail,
598                insn_detail = SparcInsnDetail<'a>,
599                op = SparcOperand,
600                feature = "arch_sparc",
601                /// Returns the SPARC details, if any
602                => arch_name = sparc,
603            ]
604            [
605                detail = Tms320c64xDetail,
606                insn_detail = Tms320c64xInsnDetail<'a>,
607                op = Tms320c64xOperand,
608                feature = "arch_tms320c64x",
609                /// Returns the Tms320c64x details, if any
610                => arch_name = tms320c64x,
611            ]
612            [
613                detail = TriCoreDetail,
614                insn_detail = TriCoreInsnDetail<'a>,
615                op = TriCoreOperand,
616                feature = "arch_tricore",
617                /// Returns the TriCore details, if any
618                => arch_name = tricore,
619            ]
620            [
621                detail = X86Detail,
622                insn_detail = X86InsnDetail<'a>,
623                op = X86Operand,
624                feature = "arch_x86",
625                /// Returns the X86 details, if any
626                => arch_name = x86,
627            ]
628            [
629                detail = XcoreDetail,
630                insn_detail = XcoreInsnDetail<'a>,
631                op = XcoreOperand,
632                feature = "arch_xcore",
633                /// Returns the XCore details, if any
634                => arch_name = xcore,
635            ]
636            [
637                detail = BpfDetail,
638                insn_detail = BpfInsnDetail<'a>,
639                op = BpfOperand,
640                feature = "arch_bpf",
641                /// Returns the BPF details, if any
642                => arch_name = bpf,
643            ]
644            [
645                detail = SysZDetail,
646                insn_detail = SysZInsnDetail<'a>,
647                op = SysZOperand,
648                feature = "arch_sysz",
649                /// Returns the SysZ details, if any
650                => arch_name = sysz,
651            ]
652        );
653    };
654}
655
656/// Define ArchDetail enum, ArchOperand enum, and From<$Operand> for ArchOperand
657macro_rules! detail_defs {
658    (
659        $( [
660            detail = $Detail:tt,
661            insn_detail = $InsnDetail:ty,
662            op = $Operand:tt,
663            feature = $feature:literal,
664            $( #[$func_attr:meta] )+
665            => arch_name = $arch_name:ident,
666        ] )+
667    ) => {
668        $(
669            #[cfg(feature = $feature)]
670            use self::$arch_name::*;
671        )+
672
673        /// Contains architecture-dependent detail structures.
674        ///
675        /// For convenience, there are methods for each architecture that return an `Option` of that
676        /// architecture's detail structure. This allows you to use an `if let Some(...) = { /* ... */ }`
677        /// instead of a match statement.
678        #[derive(Debug)]
679        pub enum ArchDetail<'a> {
680            $(
681                #[cfg(feature = $feature)]
682                $Detail($InsnDetail),
683            )+
684        }
685
686        /// Architecture-independent enum of operands
687        #[derive(Clone, Debug, PartialEq)]
688        pub enum ArchOperand {
689            $(
690                #[cfg(feature = $feature)]
691                $Operand($Operand),
692            )+
693        }
694
695        impl<'a> ArchDetail<'a> {
696            /// Returns architecture independent set of operands
697            pub fn operands(&'a self) -> Vec<ArchOperand> {
698                match *self {
699                    $(
700                        #[cfg(feature = $feature)]
701                        ArchDetail::$Detail(ref detail) => {
702                            let ops = detail.operands();
703                            let map = ops.map(ArchOperand::from);
704                            let vec: Vec<ArchOperand> = map.collect();
705                            vec
706                        }
707                    )+
708                }
709            }
710
711            $(
712                $( #[$func_attr] )+
713                #[cfg(feature = $feature)]
714                pub fn $arch_name(&'a self) -> Option<&'a $InsnDetail> {
715                    // disable warnings when only one arch is enabled
716                    #[allow(irrefutable_let_patterns)]
717                    if let ArchDetail::$Detail(ref arch_detail) = *self {
718                        Some(arch_detail)
719                    } else {
720                        None
721                    }
722                }
723            )+
724        }
725
726        $(
727            #[cfg(feature = $feature)]
728            impl From<$Operand> for ArchOperand {
729                fn from(op: $Operand) -> ArchOperand {
730                    ArchOperand::$Operand(op)
731                }
732            }
733        )+
734    }
735}
736
737/// Define OperandIterator and DetailsArch impl
738macro_rules! def_arch_details_struct {
739    (
740        InsnDetail = $InsnDetail:ident;
741        Operand = $Operand:ident;
742        OperandIterator = $OperandIterator:ident;
743        OperandIteratorLife = $OperandIteratorLife:ty;
744        [ $iter_struct:item ]
745        cs_arch_op = $cs_arch_op:ty;
746        cs_arch = $cs_arch:ty;
747    ) => {
748        /// Iterates over instruction operands
749        #[derive(Clone)]
750        $iter_struct
751
752        impl<'a> $OperandIteratorLife {
753            fn new(ops: &[$cs_arch_op]) -> $OperandIterator<'_> {
754                $OperandIterator(ops.iter())
755            }
756        }
757
758        impl<'a> Iterator for $OperandIteratorLife {
759            type Item = $Operand;
760
761            fn next(&mut self) -> Option<Self::Item> {
762                self.0.next().map($Operand::from)
763            }
764
765            fn size_hint(&self) -> (usize, Option<usize>) {
766                self.0.size_hint()
767            }
768        }
769
770        impl<'a> ExactSizeIterator for $OperandIteratorLife {
771            fn len(&self) -> usize { self.0.len() }
772        }
773
774        impl<'a> PartialEq for $OperandIteratorLife {
775            fn eq(&self, other: & $OperandIteratorLife) -> bool {
776                self.len() == other.len() && {
777                    let self_clone: $OperandIterator = self.clone();
778                    let other_clone: $OperandIterator = (*other).clone();
779                    self_clone.zip(other_clone).all(|(a, b)| a == b)
780                }
781            }
782        }
783
784        impl<'a> ::core::fmt::Debug for $OperandIteratorLife {
785            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::core::fmt::Result {
786                fmt.debug_struct(stringify!($OperandIterator)).finish()
787            }
788        }
789
790        impl<'a> ::core::fmt::Debug for $InsnDetail<'a> {
791            fn fmt(&self, fmt: &mut fmt::Formatter) -> ::core::fmt::Result {
792                fmt.debug_struct(stringify!($InsnDetail))
793                    .field(stringify!($cs_arch), &(self.0 as *const $cs_arch))
794                    .finish()
795            }
796        }
797
798        impl<'a> crate::arch::DetailsArchInsn for $InsnDetail<'a> {
799            type OperandIterator = $OperandIteratorLife;
800            type Operand = $Operand;
801
802            fn operands(&self) -> $OperandIteratorLife {
803                $OperandIterator::new(&self.0.operands[..self.0.op_count as usize])
804            }
805        }
806    }
807}
808
809detail_arch_base!(detail_defs);
810
811/// Define "pub mod" uses
812macro_rules! define_arch_mods {
813    (
814        $( [
815            ( $arch:ident, $arch_variant:ident, $feature:literal )
816            ( mode: $( $mode:ident, )+ )
817            ( extra_modes: $( $extra_mode:ident, )* )
818            ( syntax: $( $syntax:ident, )* )
819            ( both_endian: $( $endian:expr )* )
820        ] )+
821    ) => {
822        $(
823            #[cfg(feature = $feature)]
824            pub mod $arch;
825        )+
826    }
827}
828
829// Define modules at the end so that they can see macro definitions
830arch_info_base!(define_arch_mods);