1 /// Idiomatic lifting of $(LINK2 http://www.capstone-engine.org, Capstone)'s C API to D
2 module capstone.api;
3 
4 import std.typecons: BitFlags, Yes;
5 
6 import capstone.internal;
7 import capstone.capstone: Capstone;
8 
9 /// Architecture type
10 enum Arch{
11     arm = 0,    /// ARM architecture (including Thumb, Thumb-2)
12     arm64,      /// ARM-64 (also called AArch64)
13     mips,       /// Mips architecture
14     x86,        /// X86 architecture (including x86 & x86-64)
15     ppc,        /// PowerPC architecture
16     sparc,      /// Sparc architecture
17     sysz,       /// SystemZ architecture
18     xcore,      /// XCore architecture
19     m68k,		/// 68K architecture
20     tms320c64x,	/// TMS320C64x architecture
21     m680x,		/// 680X architecture
22     evm,        /// Ethereum architecture
23 }
24 
25 /// The support options that Capstone can be compiled with
26 enum SupportQuery {
27     arm = 0,      /// Support for ARM architecture (including Thumb, Thumb-2)
28     arm64,        /// Support for ARM-64 (also called AArch64)
29     mips,         /// Support for Mips architecture
30     x86,          /// Support for X86 architecture (including x86 & x86-64)
31     ppc,          /// Support for PowerPC architecture
32     sparc,        /// Support for Sparc architecture
33     sysz,         /// Support for SystemZ architecture
34     xcore,        /// Support for XCore architecture
35     m68k,		  /// 68K architecture
36     tms320c64x,	  /// TMS320C64x architecture
37     m680x,		  /// 680X architecture
38     evm,          /// Ethereum architecture
39     all = 0xFFFF, /// Supports all architectures
40     diet,         /// Compiled in diet mode, i.e. missing less relevant data fields
41     x86reduce     /// Compiled in X86-reduce mode, i.e. missing less relevant data fields and exotic X86 instruction sets
42 }
43 
44 /// Mode type
45 enum Mode {
46     littleEndian = 0,      /// Little-endian mode (default mode)
47     arm = 0,               /// 32-bit ARM
48     bit16 = 1 << 1,        /// 16-bit mode (X86)
49     bit32 = 1 << 2,        /// 32-bit mode (X86)
50     bit64 = 1 << 3,        /// 64-bit mode (X86, PPC)
51     armThumb = 1 << 4,     /// ARM's Thumb mode, including Thumb-2
52     armCortexM = 1 << 5,   /// ARM's Cortex-M series
53     armV8 = 1 << 6,        /// ARMv8 A32 encodings for ARM
54     mipsMicro = 1 << 4,    /// MicroMips mode (MIPS)
55     mips3 = 1 << 5,        /// Mips III ISA
56     mips32r6 = 1 << 6,     /// Mips32r6 ISA
57     mips2 = 1 << 7,        /// Mips II ISA
58     sparcV9 = 1 << 4,      /// SparcV9 mode (Sparc)
59 	qpx = 1 << 4,          /// Quad Processing eXtensions mode (PPC)
60     m68k_000 = 1 << 1,     /// M68K 68000 mode
61 	m68k_010 = 1 << 2,     /// M68K 68010 mode
62 	m68k_020 = 1 << 3,     /// M68K 68020 mode
63 	m68k_030 = 1 << 4,     /// M68K 68030 mode
64 	m68k_040 = 1 << 5,     /// M68K 68040 mode
65     m68k_060 = 1 << 6,     /// M68K 68060 mode
66     bigEndian = 1 << 31,   /// Big-endian mode
67     mips32 = bit32,        /// Mips32 ISA (Mips)
68     mips64 = bit64,        /// Mips64 ISA (Mips)
69     m680x_6301 = 1 << 1,   /// M680X Hitachi 6301,6303 mode
70     m680x_6309 = 1 << 2,   /// M680X Hitachi 6309 mode
71     m680x_6800 = 1 << 3,   /// M680X Motorola 6800,6802 mode
72     m680x_6801 = 1 << 4,   /// M680X Motorola 6801,6803 mode
73     m680x_6805 = 1 << 5,   /// M680X Motorola/Freescale 6805 mode
74     m680x_6808 = 1 << 6,   /// M680X Motorola/Freescale/NXP 68HC08 mode
75     m680x_6809 = 1 << 7,   /// M680X Motorola 6809 mode
76     m680x_6811 = 1 << 8,   /// M680X Motorola/Freescale/NXP 68HC11 mode
77     m680x_cpu12 = 1 << 9,  /// M680X Motorola/Freescale/NXP CPU12
78     m680x_hcs08 = 1 << 10, /// M680X Freescale/NXP HCS08 mode
79 }
80 /** Alias for combination of several modes
81 
82 Example:
83 ---
84 auto flags = ModeFlags(Mode.arm + Mode.armV8);
85 ---
86 */
87 alias ModeFlags = BitFlags!(Mode, Yes.unsafe);
88 
89 
90 /// Disassembly syntax variants
91 enum Syntax {
92 	systemDefault = 0, /// System's default syntax
93 	intel,             /// X86 Intel syntax - default on X86
94 	att,               /// X86 AT&T syntax
95 	noregname,         /// Prints register name with only number
96     masm,              /// X86 Intel Masm syntax
97 }
98 
99 /** User-defined callback function type for SKIPDATA mode of operation
100  
101 The first parameter is the input buffer containing code to be disassembled,
102 while the second one holds the position of the currently-examined byte in this buffer.
103 
104 Returns: The number of bytes to skip, or 0 to immediately stop disassembling
105 
106 Example:
107 ---
108 size_t callback(in ubyte[] code, size_t offset) {
109     return 2; // Always skip 2 bytes when encountering uninterpretable instructions
110 }
111 ---
112 See `Capstone.setupSkipdata` documentation for full sample code demonstrating this functionality.
113 */
114 alias Callback = size_t delegate(in ubyte[] code, size_t offset) nothrow @nogc;
115 
116 // This trampoline is the ugly C-lang callback (calling D in turn)
117 package extern(C) size_t cCallback(const(ubyte)* code, size_t code_size, size_t offset, void* userData) nothrow @nogc{
118     auto slice = code[0..code_size];
119     
120     // Call the nice d-lang callback
121     auto dCallback = *cast(Callback*)userData;
122     auto res = dCallback(slice, offset);
123     return res;
124 }
125 
126 /// Version consisting of major and minor numbers
127 struct Version{
128     int major; /// Major version number
129     int minor; /// Minor version number
130 
131     /// Textual representation
132     string toString() const {
133         import std.format: format;
134         return "%s.%s".format(major, minor);
135     }
136 }
137 
138 /// Determines the `Version` supported by these bindings
139 auto versionOfBindings() {
140     return Version(CS_API_MAJOR, CS_API_MINOR);
141 }
142 
143 /// Determines the `Version` supported by the installed library
144 auto versionOfLibrary() {
145     int major, minor;
146     cs_version(&major, &minor);
147     return Version(major, minor);
148 }
149 ///
150 unittest{
151     import std.format: format;
152     const libVer = versionOfLibrary;
153     const bindVer = versionOfBindings;        
154     assert(libVer == bindVer, "API version mismatch between library (%s) and bindings (%s)".format(libVer, bindVer));
155 }
156 
157 /** Indicates whether the installed library was compiled in $(LINK2 http://www.capstone-engine.org/diet.html, diet mode)
158 
159 Convenience functionality which is also available via `supports`.
160 */
161 bool diet(){
162     return supports(SupportQuery.diet);
163 }
164 
165 /** Indicates whether an architecture or particular option is supported by the installed Capstone library
166 
167 Params:
168     query = The `SupportQuery` to issue to the library
169  
170 Returns: True if the requested option is supported
171 
172 Example:
173 ---
174 // Query installed Capstone library for supported options
175 foreach(query; EnumMembers!SupportQuery)
176     writefln!"%-10s: %s"(query, supports(query));
177 ---
178 */
179 bool supports(in SupportQuery query){
180     return cs_support(query);
181 }
182 
183 /// Common instruction operand access types - to be consistent across all architectures.
184 enum AccessType {
185     invalid = 0,      /// Uninitialized/invalid access type.
186 	read    = 1 << 0, /// Operand read from memory or register.
187 	write   = 1 << 1, /// Operand write to memory or register.
188 }
189 /** Alias for combination of several flags
190 
191 Example:
192 ---
193 auto flags = AccessFlags(AccessType.read | AccessType.write);
194 ---
195 */
196 alias AccessFlags = BitFlags!AccessType;
197 
198 // TODO: Rename to capstone?
199 /** Creates a Capstone instance for disassembling code of a specific architecture
200 Params:
201     arch = The architecture to interpret the bytestream for
202     modeFlags = The mode of interpretation
203 
204 Example:
205 ---
206 auto cs = create(Arch.x86, ModeFlags(Mode.bit32));
207 ---
208  */
209 static Capstone create(Arch arch, ModeFlags modeFlags){
210     import std.format: format;
211     import capstone.arm: CapstoneArm;
212     import capstone.arm64: CapstoneArm64;
213     import capstone.evm: CapstoneEvm;
214     import capstone.m68k: CapstoneM68k;
215     import capstone.m680x: CapstoneM680x;
216     import capstone.mips: CapstoneMips;
217     import capstone.ppc: CapstonePpc;
218     import capstone.sparc: CapstoneSparc;
219     import capstone.sysz: CapstoneSysz;
220     import capstone.tms320c64x: CapstoneTms320c64x;
221     import capstone.x86: CapstoneX86;
222     import capstone.xcore: CapstoneXCore;
223     import capstone.error: CapstoneException, ErrorCode;
224 
225     switch(arch){
226         case Arch.arm: return new CapstoneArm(modeFlags);
227         case Arch.arm64: return new CapstoneArm64(modeFlags);
228         case Arch.evm: return new CapstoneEvm(modeFlags);
229         case Arch.m68k: return new CapstoneM68k(modeFlags);
230         case Arch.m680x: return new CapstoneM680x(modeFlags);
231         case Arch.mips: return new CapstoneMips(modeFlags);
232         case Arch.ppc: return new CapstonePpc(modeFlags);
233         case Arch.sparc: return new CapstoneSparc(modeFlags);
234         case Arch.sysz: return new CapstoneSysz(modeFlags);
235         case Arch.tms320c64x: return new CapstoneTms320c64x(modeFlags);
236         case Arch.x86: return new CapstoneX86(modeFlags);
237         case Arch.xcore: return new CapstoneXCore(modeFlags);
238         default:
239             throw new CapstoneException("%s architecture not yet supported by bindings".format(arch), ErrorCode.UnsupportedArchitecture);
240     }
241 }