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: Tuple, BitFlags, Yes, Nullable;
5 import std.exception: enforce, assertThrown;
6 import std.format;
7 import std.conv;
8 import std..string;
9 import std.array;
10 import std.range: isInputRange;
11 import std.algorithm: canFind;
12 import std.traits: EnumMembers;
13 
14 import capstone;
15 
16 // Aliases
17 alias CapstoneArm = CapstoneImpl!(Arch.arm);
18 alias InstructionArm = InstructionImpl!(Arch.arm);
19 alias CapstoneArm64 = CapstoneImpl!(Arch.arm64);
20 alias InstructionArm64 = InstructionImpl!(Arch.arm64);
21 alias CapstoneMips = CapstoneImpl!(Arch.mips);
22 alias InstructionMips = InstructionImpl!(Arch.mips);
23 alias CapstonePpc = CapstoneImpl!(Arch.ppc);
24 alias InstructionPpc = InstructionImpl!(Arch.ppc);
25 alias CapstoneSparc = CapstoneImpl!(Arch.sparc);
26 alias InstructionSparc = InstructionImpl!(Arch.sparc);
27 alias CapstoneSysz = CapstoneImpl!(Arch.sysz);
28 alias InstructionSysz = InstructionImpl!(Arch.sysz);
29 alias CapstoneX86 = CapstoneImpl!(Arch.x86);
30 alias InstructionX86 = InstructionImpl!(Arch.x86);
31 alias CapstoneXCore = CapstoneImpl!(Arch.xcore);
32 alias InstructionXCore = InstructionImpl!(Arch.xcore);
33 
34 /// Architecture type
35 enum Arch{
36     arm = 0, /// ARM architecture (including Thumb, Thumb-2)
37     arm64,   /// ARM-64 (also called AArch64)
38     mips,    /// Mips architecture
39     x86,     /// X86 architecture (including x86 & x86-64)
40     ppc,     /// Support for PowerPC architecture
41     sparc,   /// Support for Sparc architecture
42     sysz,    /// Support for SystemZ architecture
43     xcore    /// Support for XCore architecture
44 }
45 
46 /// The support options that Capstone can be compiled with
47 enum SupportQuery {
48     arm = 0,      /// Support for ARM architecture (including Thumb, Thumb-2)
49     arm64,        /// Support for ARM-64 (also called AArch64)
50     mips,         /// Support for Mips architecture
51     x86,          /// Support for X86 architecture (including x86 & x86-64)
52     powerPc,      /// Support for PowerPC architecture
53     sparc,        /// Support for Sparc architecture
54     systemZ,      /// Support for SystemZ architecture
55     xCore,        /// Support for XCore architecture
56     all = 0xFFFF, /// Supports all architectures
57     diet,         /// Compiled in diet mode, i.e. missing less relevant data fields
58     x86Reduce     /// Compiled in X86-reduce mode, i.e. missing less relevant data fields and exotic X86 instruction sets
59 }
60 
61 /// Mode type
62 enum Mode {
63     littleEndian = 0,   /// Little-endian mode (default mode)
64     arm = 0,            /// 32-bit ARM
65     bit16 = 1 << 1,     /// 16-bit mode (X86)
66     bit32 = 1 << 2,     /// 32-bit mode (X86)
67     bit64 = 1 << 3,     /// 64-bit mode (X86, PPC)
68     armThumb = 1 << 4,  /// ARM's Thumb mode, including Thumb-2
69     armCortexM = 1 << 5,/// ARM's Cortex-M series
70     armV8 = 1 << 6,     /// ARMv8 A32 encodings for ARM
71     mipsMicro = 1 << 4, /// MicroMips mode (MIPS)
72     mips3 = 1 << 5,     /// Mips III ISA
73     mips32r6 = 1 << 6,  /// Mips32r6 ISA
74     mipsGp64 = 1 << 7,  /// General Purpose Registers are 64-bit wide (MIPS)
75     bigEndian = 1 << 31,/// SparcV9 mode (Sparc)
76     sparcV9 = 1 << 4,   /// Big-endian mode
77     mips32 = bit32,     /// Mips32 ISA (Mips)
78     mips64 = bit64      /// Mips64 ISA (Mips)
79 }
80 /// Type for combination of several modes
81 alias ModeFlags = BitFlags!(Mode, Yes.unsafe);
82 
83 /// Disassembly syntax variants
84 enum Syntax {
85 	systemDefault = 0, /// System's default syntax
86 	intel,             /// X86 Intel syntax - default on X86
87 	att,               /// X86 AT&T syntax
88 	noregname          /// Prints register name with only number
89 }
90 
91 // Auxiliary templates to derive the types to use as InstructionId, Register, InstructionGroup and InstructionDetail for a given architecture
92 private{
93     import std.meta: AliasSeq;
94     template ArchSpec(Arch arch){
95         static if(arch == Arch.arm)
96             alias ArchSpec = AliasSeq!(ArmInstructionId, ArmRegister, ArmInstructionGroup, ArmInstructionDetail);
97         else static if(arch == Arch.arm64)
98             alias ArchSpec = AliasSeq!(Arm64InstructionId, Arm64Register, Arm64InstructionGroup, Arm64InstructionDetail);
99         else static if(arch == Arch.mips)
100             alias ArchSpec = AliasSeq!(MipsInstructionId, MipsRegister, MipsInstructionGroup, MipsInstructionDetail);
101         else static if(arch == Arch.ppc)
102             alias ArchSpec = AliasSeq!(PpcInstructionId, PpcRegister, PpcInstructionGroup, PpcInstructionDetail);
103         else static if(arch == Arch.sparc)
104             alias ArchSpec = AliasSeq!(SparcInstructionId, SparcRegister, SparcInstructionGroup, SparcInstructionDetail);
105         else static if(arch == Arch.sysz)
106             alias ArchSpec = AliasSeq!(SyszInstructionId, SyszRegister, SyszInstructionGroup, SyszInstructionDetail);
107         else static if(arch == Arch.x86)
108             alias ArchSpec = AliasSeq!(X86InstructionId, X86Register, X86InstructionGroup, X86InstructionDetail);
109         else static if(arch == Arch.xcore)
110             alias ArchSpec = AliasSeq!(XCoreInstructionId, XCoreRegister, XCoreInstructionGroup, XCoreInstructionDetail);
111         else static assert(false);
112     }
113     alias InstructionId(Arch arch) = ArchSpec!(arch)[0];
114     alias Register(Arch arch) = ArchSpec!(arch)[1];
115     alias InstructionGroup(Arch arch) = ArchSpec!(arch)[2];
116     alias InstructionDetail(Arch arch) = ArchSpec!(arch)[3];
117 }
118 
119 /// Instruction detail 
120 struct Detail(Arch arch) {
121 	Register!arch[] regsRead;       /// Registers implicitly read by this instruction
122 	Register!arch[] regsWrite;      /// Registers implicitly modified by this instruction
123 	InstructionGroup!arch[] groups; /// The groups this instruction belongs to
124 
125 	/// Architecture-specific instruction detail
126     InstructionDetail!arch archSpecific;
127     /// Convenience-alias making `archSpecific`'s members directly accessible from this
128     alias archSpecific this;
129 
130     private this(cs_detail internal){
131         regsRead = internal.regs_read[0..internal.regs_read_count].to!(Register!arch[]);
132         regsWrite = internal.regs_write[0..internal.regs_write_count].to!(Register!arch[]);
133         groups = internal.groups[0..internal.groups_count].to!(InstructionGroup!arch[]);
134         archSpecific = InstructionDetail!arch(internal.arch_detail);
135     }
136 }
137 
138 /// Architecture-independent instruction
139 abstract class Instruction {
140 	ulong address;         /// Address (EIP) of this instruction
141 	ubyte[] bytes;         /// Machine bytes of this instruction
142 	string mnemonic;       /// Ascii text of instruction mnemonic
143 	string opStr;          /// Ascii text of instruction operands
144 	
145     private this(cs_insn internal){
146         address = internal.address;
147         bytes = internal.bytes[0..internal.size].dup;
148         mnemonic = internal.mnemonic.ptr.to!string;
149         opStr = internal.op_str.ptr.to!string;
150     }
151 }
152 
153 /// Architecture-specific instruction
154 class InstructionImpl(Arch arch) : Instruction {
155 	InstructionId!arch id; /// Instruction ID (basically a numeric ID for the instruction mnemonic)
156     private Nullable!(Detail!arch) _detail;
157 
158     private this(cs_insn internal, bool detail, bool skipData){
159         super(internal);
160         id = internal.id.to!(InstructionId!arch);
161 
162         if(detail && !skipData)
163             _detail = Detail!arch(*internal.detail);
164     }
165     /** More details about the instruction
166     
167     Note that this is only available if both requirements are met: 
168     $(OL
169         $(LI details are enabled)
170         $(LI the engine is not in Skipdata mode))
171     */ 
172     @property detail() const {
173         if(_detail.isNull)
174             throw new CapstoneException("Trying to access unavailable instruction detail", ErrorCode.UnavailableInstructionDetail);
175         return _detail;
176     }
177 
178     /** Checks whether the instruction belongs to the instruction group `group`
179 
180     Convenience method for searching through `detail.groups`.
181     */
182     bool isInGroup(InstructionGroup!arch group) const {
183         return detail.groups.canFind(group);
184     }
185 
186     /** Checks if the instruction IMPLICITLY uses a particular register
187 
188     Convenience method for searching through `detail.readRegs`.
189     */
190     bool readsReg(Register!arch reg) const {
191         return detail.regsRead.canFind(reg);
192     }
193 
194     /** Checks if the instruction IMPLICITLY modifies a particular register
195 
196     Convenience method for searching through `detail.writeRegs`.
197     */
198     bool writesReg(Register!arch reg) const {
199         return detail.regsWrite.canFind(reg);
200     }
201 }
202 
203 /** User-defined callback function type for SKIPDATA mode of operation
204  
205 The first parameter is the input buffer containing code to be disassembled,
206 while the second one holds the position of the currently-examined byte in this buffer.
207 
208 Returns: The number of bytes to skip, or 0 to immediately stop disassembling
209 
210 Example:
211 ---
212 size_t callback(in ubyte[] code, size_t offset) {
213     return 2; // Always skip 2 bytes when encountering uninterpretable instructions
214 }
215 ---
216 See `setupSkipdata` documentation for full sample code demonstrating this functionality.
217 */
218 alias Callback = size_t delegate(in ubyte[] code, size_t offset) nothrow @nogc;
219 
220 // This trampoline is the ugly C-lang callback (calling D in turn)
221 private extern(C) size_t cCallback(const(ubyte)* code, size_t code_size, size_t offset, void* userData) nothrow @nogc{
222     auto slice = code[0..code_size];
223     
224     // Call the nice d-lang callback
225     auto dCallback = *cast(Callback*)userData;
226     auto res = dCallback(slice, offset);
227     return res;
228 }
229 
230 /// Version consisting of major and minor numbers
231 struct Version{
232     int major; /// Major version number
233     int minor; /// Minor version number
234 
235     /// Textual representation
236     string toString() const {
237         return "%s.%s".format(major, minor);
238     }
239 }
240 
241 /// Determines the `Version` supported by these bindings
242 auto versionOfBindings() {
243     return Version(CS_API_MAJOR, CS_API_MINOR);
244 }
245 
246 /// Determines the `Version` supported by the installed library
247 auto versionOfLibrary() {
248     int major, minor;
249     cs_version(&major, &minor);
250     return Version(major, minor);
251 }
252 ///
253 unittest{
254     const libVer = versionOfLibrary;
255     const bindVer = versionOfBindings;        
256     assert(libVer == bindVer, "API version mismatch between library (%s) and bindings (%s)".format(libVer, bindVer));
257 }
258 
259 /** Indicates whether the installed library was compiled in $(LINK2 http://www.capstone-engine.org/diet.html, diet mode)
260 
261 Convenience functionality which is also available via `supports`.
262 */
263 auto diet(){
264     return supports(SupportQuery.diet);
265 }
266 
267 /** Indicates whether an architecture or particular option is supported by the installed Capstone library
268 
269 Params:
270     query = The `SupportQuery` to issue to the library
271  
272 Returns: True if the requested option is supported
273 
274 Example:
275 ---
276 // Query installed Capstone library for supported options
277 foreach(query; EnumMembers!SupportQuery)
278     writefln!"%-10s: %s"(query, supports(query));
279 ---
280 */
281 auto supports(in SupportQuery query){
282     return cs_support(query);
283 }
284 
285 /** Encapsulates an instance of the Capstone dissassembly engine
286 
287 This class encapsulates the core functionality of the Capstone disassembly engine, providing
288 access to runtime options for
289 $(UL
290     $(LI changing the `Mode` of interpretation)
291     $(LI changing the `Syntax` of the disassembly)
292     $(LI choosing whether `Instruction`'s should be disassembled in detail, i.e. filling `Instruction.detail`)
293     $(LI defining manual handling of broken instructions through the $(LINK2 http://www.capstone-engine.org/skipdata.html, SKIPDATA) mode of operation (optionally via a `Callback`))
294 )
295 
296 Note that, since the architecture is chosen at runtime, this base class only gives access to the architecture-indepentent aspects,
297 but can be cast to the `CapstoneImpl` of corresponding architecture.
298 */
299 abstract class Capstone{
300     private{
301         alias Handle = size_t;
302         Handle handle;    
303         
304         ModeFlags _mode;
305         Syntax _syntax;
306         bool _detail;
307         bool _skipData;
308 
309         string mnemonic;
310         Callback callback;
311     }
312     const Arch arch;
313 
314     /** Constructs an instance of the disassembly engine
315 
316     Params:
317         modeFlags = A combination of flags to further specify how bytes will be interpreted, e.g. in little-endian.
318     */
319     private this(in Arch arch, in ModeFlags modeFlags){
320         const libVer = versionOfLibrary;
321         const bindVer = versionOfBindings;
322         if(libVer != bindVer)
323             throw new CapstoneException("API version mismatch between library (%s) and bindings (%s)".format(libVer, bindVer), ErrorCode.UnsupportedVersion);
324 
325         // Create Capstone engine instance
326         this.arch = arch;
327         this._mode = modeFlags;
328         cs_open(arch, modeFlags.to!uint, &handle).checkErrno;
329 
330         // Sync members with library's default values
331         // Note: not really necessary at the time of writing as they happen to match
332         syntax = _syntax;
333         detail = _detail;
334         skipData = _skipData;
335     }
336 
337     ~this(){
338         if(handle)
339            cs_close(&handle).checkErrno;
340     }
341     
342     /** Creates a Capstone instance for disassembling code of a specific architecture
343 
344     Params:
345         arch = The architecture to interpret the bytestream for
346         modeFlags = The mode of interpretation
347      */
348     static Capstone create(Arch arch, ModeFlags modeFlags){
349         final switch(arch){
350             case Arch.arm:
351                 return new CapstoneImpl!(Arch.arm)(modeFlags);
352             case Arch.arm64:
353                 return new CapstoneImpl!(Arch.arm64)(modeFlags);
354             case Arch.mips:
355                 return new CapstoneImpl!(Arch.mips)(modeFlags);
356             case Arch.ppc:
357                 return new CapstoneImpl!(Arch.ppc)(modeFlags);
358             case Arch.sparc:
359                 return new CapstoneImpl!(Arch.sparc)(modeFlags);
360             case Arch.sysz:
361                 return new CapstoneImpl!(Arch.sysz)(modeFlags);
362             case Arch.x86:
363                 return new CapstoneImpl!(Arch.x86)(modeFlags);
364             case Arch.xcore:
365                 return new CapstoneImpl!(Arch.xcore)(modeFlags);
366         }
367     }
368 
369     /// Gets the mode of interpretation
370     @property auto mode() const {return _mode;}
371     /// Sets the mode of interpretation
372     @property void mode(in ModeFlags modeFlags){
373         _mode = modeFlags;
374         cs_option(handle, cs_opt_type.CS_OPT_MODE, modeFlags.to!uint).checkErrno;
375     }
376 
377     /// Gets the disassembly syntax variant
378     @property auto syntax() const {return _syntax;}
379     /// Sets the disassembly syntax variant
380     @property void syntax(in Syntax option){
381         _syntax = option;
382         cs_option(handle, cs_opt_type.CS_OPT_SYNTAX, option).checkErrno;
383     }
384 
385     /// Indicates whether instructions will be disassembled in detail
386     @property auto detail() const {return _detail;}
387     /// Sets whether instructions will be disassembled in detail
388     @property void detail(in bool enable){
389         _detail = enable;
390         auto option = (enable ? cs_opt_value.CS_OPT_ON : cs_opt_value.CS_OPT_OFF);
391         cs_option(handle, cs_opt_type.CS_OPT_DETAIL, option).checkErrno;
392     }
393 
394     /// Indicates whether SKIPDATA mode of operation is in use
395     @property auto skipData() const {return _skipData;}
396     /// Sets whether to use SKIPDATA mode of operation
397     @property void skipData(in bool enable){
398         _skipData = enable;
399         auto option = (enable ? cs_opt_value.CS_OPT_ON : cs_opt_value.CS_OPT_OFF);
400         cs_option(handle, cs_opt_type.CS_OPT_SKIPDATA, option).checkErrno;
401     }
402 
403     /** Customises behaviour in SKIPDATA mode of operation
404      
405     By default, disassembling will stop when it encounters a broken instruction.
406     Most of the time, the reason is that this is data mixed inside the input.
407 
408     When in SKIPDATA mode, some (unknown) amount of data until the next interpretable instruction will be skipped.
409     Capstone considers the skipped data a special instruction with ID 0x00 and a `mnemonic` that defaults to `".byte"`.
410     The operand string is a hex-code of the sequence of bytes it skipped.
411 
412     By default, for each iteration, Capstone skips 1 byte on X86 architecture, 2 bytes on Thumb mode on Arm
413     architecture, and 4 bytes for the rest. The reason while Capstone skips 1 byte on X86 is that X86 puts no
414     restriction on instruction alignment, but other architectures enforce some requirements on this aspect.
415 
416     To customise how many bytes to skip when encountering data, a `Callback` delegate can optonally be setup
417     to return the corresponding number.
418 
419     Params:
420         mnemonic = The mnemonic to use for representing skipped data
421         callback = The optional callback to use for handling bytes that cannot be interpreted as an instruction.
422     
423     Example:
424     ---
425     // Custom data that can be referred to in a callback delegate
426     struct CallbackData{
427         int bytesToSkip;
428     }
429     auto myData = CallbackData(1);
430     size_t myCallback(in ubyte[] code, size_t offset) {
431         return myData.bytesToSkip++; // Always skip one more byte when encountering data
432     }
433     cs.skipData = true;                     // Enable skipdata mode
434     cs.setupSkipdata("db", &myCallback);    // Use custom callback, and "db" as custom mnemonic for data
435     ---
436     */
437     void setupSkipdata(in string mnemonic = ".byte", Callback callback = null){
438         if(!mnemonic)
439             throw new CapstoneException("Invalid mnemonic", ErrorCode.InvalidOption);
440         this.mnemonic = mnemonic;
441         this.callback = callback;
442         
443         auto setup = cs_opt_skipdata(this.mnemonic.ptr, this.callback ? &cCallback : null, &this.callback);
444         cs_option(handle, cs_opt_type.CS_OPT_SKIPDATA_SETUP, cast(size_t)&setup).checkErrno;
445     }
446 
447     /** Disassemble binary code, given the code buffer, start address and number of instructions to be decoded
448     
449     For systems with scarce memory, the API `disasmIter` might be a better choice than `disasm`
450     Params:
451         code    = Buffer containing raw binary code to be disassembled
452         address = Address of the first instruction in given raw code buffer
453         count   = Number of instructions to be disassembled, or 0 to get all of them
454     Returns: The successfully disassembled instructions
455 
456     Example:
457     ---
458     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
459     auto cs = new CapstoneX86(ModeFlags(Mode.bit32)); // Initialise x86 32bit engine
460     auto res = cs.disasm(CODE, 0x1000);               // Disassemble, offsetting addresses by 0x1000
461     assert("%s %s".format(res[0].mnemonic, res[0].opStr) == "lea ecx, dword ptr [edx + esi + 8]");
462     assert("%s %s".format(res[1].mnemonic, res[1].opStr) == "add eax, ebx");
463     assert("%s %s".format(res[2].mnemonic, res[2].opStr) == "add esi, 0x1234");
464     ---
465     */
466     abstract const(Instruction)[] disasm(in ubyte[] code, in ulong address, in size_t count = 0);
467 
468     /** Provides a range to iteratively disassemble binary code - one instruction at a time
469 
470     Fast API to disassemble binary code, given the code buffer and start address.
471     Provides access to only one disassembled instruction at a time, resulting in a smaller memory footprint.
472     Params:
473         code    = Buffer containing raw binary code to be disassembled
474         address = Address of the first instruction in given raw code buffer
475     Returns: An input range over the disassembled instructions
476 
477     Example:
478     ---
479     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
480 
481     auto cs = new CapstoneX86(ModeFlags(Mode.bit32)); // Initialise x86 32bit engine
482     auto range = cs.disasmIter(CODE, 0x1000);         // Disassemble one instruction at a time, offsetting addresses by 0x1000
483     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "lea ecx, dword ptr [edx + esi + 8]");
484     range.popFront;
485     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "add eax, ebx");
486     range.popFront;
487     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "add esi, 0x1234");
488     range.popFront;
489     assert(range.empty);
490     ---
491     */
492     abstract InstructionRange disasmIter(in ubyte[] code, in ulong address);
493 }
494 
495 /** Encapsulates an architecture-specific instance of the Capstone dissassembly engine
496 
497 Note that, in contrast to the base class, the architecture is chosen at compile-time.
498 
499 Params:
500     archParam = The architecture this Capstone instance is tailored for
501 */
502 class CapstoneImpl(Arch archParam) : Capstone { // Actually parametrised by Registers, InstructionId, InstructionDetail and InstructionGroup but those are uniquely implied by the architecture
503     /** Creates an architecture-specific instance with a given mode of interpretation
504     
505     Params:
506         modeFlags = The (initial) mode of interpretation, which can still be changed later on
507     */
508     this(in ModeFlags modeFlags){
509         super(archParam, modeFlags);
510     }
511 
512     override InstructionImpl!archParam[] disasm(in ubyte[] code, in ulong address, in size_t count = 0){
513         cs_insn* internalInstrs;
514         auto actualCount = cs_disasm(handle, code.ptr, code.length, address, count, &internalInstrs);
515         scope(exit){if(internalInstrs){cs_free(internalInstrs, actualCount);}}
516         cs_errno(handle).checkErrno;
517 
518         auto instrAppnd = appender!(InstructionImpl!archParam[]);
519         instrAppnd.reserve(actualCount);
520         foreach(instr; internalInstrs[0..actualCount])
521             instrAppnd.put(new InstructionImpl!archParam(instr, detail, skipData));
522         return instrAppnd.data;
523     }
524 
525     override InstructionImplRange!archParam disasmIter(in ubyte[] code, in ulong address){
526         return new InstructionImplRange!archParam(this, code, address);
527     }
528 
529     // TODO: Really needed? Almost identical to regular `toString`
530     /** Determines friendly name of a register
531     
532     When in diet mode, this API is irrelevant because engine does not store register names
533     Param:
534         regId = Register id
535     Returns: Friendly string representation of the register's name
536     */
537     string regName(Register!archParam regId) const {
538         if(diet)
539             throw new CapstoneException("Register names are not stored when running Capstone in diet mode",
540                 ErrorCode.IrrelevantDataAccessInDietEngine);
541         return cs_reg_name(handle, regId).to!string;
542     }
543 
544     // TODO: Really needed? Almost identical to regular `toString`
545     /** Determines friendly name of an instruction
546     
547     When in diet mode, this API is irrelevant because engine does not store instruction names
548     Param:
549         instrId = Instruction id
550     Returns: Friendly string representation of the instruction's name
551     */
552     string instrName(InstructionId!archParam instrId) const {
553         if(diet)
554             throw new CapstoneException("Instruction names are not stored when running Capstone in diet mode",
555                 ErrorCode.IrrelevantDataAccessInDietEngine);
556         return cs_insn_name(handle, instrId).to!string;
557     }
558 
559     // TODO: Really needed? Almost identical to regular `toString`
560     /** Determines friendly name of a group id (that an instruction can belong to)
561     
562     When in diet mode, this API is irrelevant because engine does not store group names
563     Param:
564         groupId = Group id
565     Returns: Friendly string representation of the group's name, or null if `groupId` is invalid
566     */
567     string groupName(InstructionGroup!archParam groupId) const {
568         if(diet)
569             throw new CapstoneException("Group names are not stored when running Capstone in diet mode",
570                 ErrorCode.IrrelevantDataAccessInDietEngine);
571         return cs_group_name(handle, groupId).to!string;
572     }
573 }
574 
575 unittest{
576     const code = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
577     auto cs = new CapstoneX86(ModeFlags(Mode.bit16));
578     cs.disasm(code, 0x1000);
579     cs.mode = ModeFlags(Mode.bit32);
580     cs.disasm(code, 0x1000);
581 }
582 
583 // TODO: Try switching to InputRange!Instruction (more restrictive than isInputRange, though)
584 /// An input range that provides access to one disassembled `Instruction` at a time
585 abstract class InstructionRange {
586     @property Instruction front();
587     @property bool empty();
588     void popFront();
589 }
590 static assert(isInputRange!InstructionRange);
591 
592 /// An extended `InstructionRange` that provides architecture-specific instructions
593 class InstructionImplRange(Arch arch) : InstructionRange {
594     import core.exception: RangeError;
595     private{
596         CapstoneImpl!arch cs;
597         const ubyte[] code; // Keep ref, s.t. it cannot be deallocated externally
598         const(ubyte)* pCode;
599         ulong codeLength;
600         ulong address;
601 
602         InstructionImpl!arch instr;
603         cs_insn* pInsn;
604 
605         bool hasFront;
606     }
607 
608     private this(CapstoneImpl!arch cs, in ubyte[] code, in ulong address){
609         this.cs = cs;
610         this.code = code;
611         this.pCode = code.ptr;
612         this.codeLength = code.length;
613         this.address = address;
614         this.hasFront = true;
615 
616         pInsn = cs_malloc(cs.handle);
617         if(!pInsn)
618             throw new CapstoneException("Insufficient memory to allocate an instruction", ErrorCode.OutOfMemory);
619         popFront;
620     }
621 
622     ~this(){
623         if(pInsn)
624             cs_free(pInsn, 1);
625     }
626 
627     /// True if no disassemblable instructions remain
628     @property override bool empty() const {return !hasFront;}
629 
630     /** The latest disassembled instruction
631 
632     Throws if called on an `empty` range.
633     */
634     @property override InstructionImpl!arch front() {
635         enforce!RangeError(!empty, "Trying to access an empty range (%s)".format(typeof(this).stringof));
636         return instr;
637     }
638 
639     /** Advances the range, disassembling the next instruction
640 
641     Throws if called on an `empty` range.
642     */
643     override void popFront(){
644         enforce!RangeError(!empty, "Trying to access an empty range (%s)".format(typeof(this).stringof));
645         hasFront = cs_disasm_iter(cs.handle, &pCode, &codeLength, &address, pInsn);
646         if(hasFront)
647             instr = new InstructionImpl!arch(*pInsn, cs.detail, cs.skipData);
648         else
649             cs_errno(cs.handle).checkErrno;
650     }
651 }
652 static assert(isInputRange!(InstructionRange));
653 
654 unittest{
655     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
656     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
657     auto instrs = cs.disasm(CODE, 0x1000);
658     assert(instrs.length == 3); // With skipdata disabled, disassembling will halt when encountering data
659     cs.skipData = true;
660     instrs = cs.disasm(CODE, 0x1000);
661     assert(instrs.length == 6);
662 }
663 
664 unittest{
665     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
666     // Custom data that can be referred to in a callback delegate
667     struct CallbackData{
668         int bytesToSkip;
669     }
670     auto myData = CallbackData(1);
671     size_t myCallback(in ubyte[] code, size_t offset) {
672         return myData.bytesToSkip++; // Always skip one more byte when encountering data
673     }
674     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
675     cs.skipData = true;                     // Enable skipdata mode
676     cs.setupSkipdata("db", &myCallback);    // Use custom callback, and "db" as custom mnemonic for data
677     const instrs = cs.disasm(CODE, 0x1000); // Disassemble (offsetting addresses by 0x1000)
678     assert(instrs.length == 6);
679 }
680 
681 unittest{
682     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
683     auto cs = new CapstoneX86(ModeFlags(Mode.bit32)); // Initialise x86 32bit engine
684     auto res = cs.disasm(CODE, 0x1000);                       // Disassemble, offsetting addresses by 0x1000
685     assert("%s %s".format(res[0].mnemonic, res[0].opStr) == "lea ecx, dword ptr [edx + esi + 8]");
686     assert("%s %s".format(res[1].mnemonic, res[1].opStr) == "add eax, ebx");
687     assert("%s %s".format(res[2].mnemonic, res[2].opStr) == "add esi, 0x1234");
688 }
689 
690 unittest{
691     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
692     auto cs = new CapstoneX86(ModeFlags(Mode.bit32)); // Initialise x86 32bit engine
693     auto range = cs.disasmIter(CODE, 0x1000);         // Disassemble one instruction at a time, offsetting addresses by 0x1000
694     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "lea ecx, dword ptr [edx + esi + 8]");
695     range.popFront;
696     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "add eax, ebx");
697     range.popFront;
698     assert("%s %s".format(range.front.mnemonic, range.front.opStr) == "add esi, 0x1234");
699     range.popFront;
700     assert(range.empty);
701     import core.exception: RangeError;       // Once empty, both `front` and `popFront` cannot be accessed
702     assertThrown!RangeError(range.front);
703     assertThrown!RangeError(range.popFront);
704 }
705 
706 unittest{
707     auto CODE = cast(ubyte[])"\x8d\x4c\x32\x08\x01\xd8\x81\xc6\x34\x12\x00\x00\x00\x91\x92";
708     
709     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
710     assert(cs.disasmIter(CODE, 0x1000).array.length == 3); // With skipdata disabled, disassembling will halt when encountering data
711     cs.skipData = true;
712     assert(cs.disasmIter(CODE, 0x1000).array.length == 6);
713 }
714 
715 unittest{
716     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
717     assert(cs.regName(X86Register.eip) == X86Register.eip.to!string); // Mostly same output as `to!string`
718     assert(cs.regName(X86Register.st7) == "st(7)");                   // Differs sometimes though
719 }
720 
721 unittest{
722     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
723     assert(cs.instrName(X86InstructionId.add) == X86InstructionId.add.to!string); // Mostly same as `to!string`
724 }
725 
726 unittest{
727     auto cs = new CapstoneX86(ModeFlags(Mode.bit32));
728     assert(cs.groupName(X86InstructionGroup.sse1) == X86InstructionGroup.sse1.to!string); // Mostly same as `to!string`
729 }
730 
731 unittest{
732     enum code = cast(ubyte[])"\x55";
733     auto cs = new CapstoneX86(ModeFlags(Mode.bit64));
734     cs.detail = true;
735 
736     auto range = cs.disasmIter(code, 0x1000);
737     auto pushInstr = range.front;                            // 0x55 disassembles to "push"
738     assert(pushInstr.mnemonic == "push");
739     assert(pushInstr.isInGroup(X86InstructionGroup.mode64)); // "push" is part of the mode64 instructions
740     assert(pushInstr.readsReg(X86Register.rsp));             // "push" accesses rsp
741     assert(pushInstr.writesReg(X86Register.rsp));            // "push" modifies rsp
742 }