1 /// Range-based iteration over disassembled instructions 2 module capstone.range; 3 4 import std.exception: enforce, assertThrown; 5 import std.range: isInputRange; 6 import std.format: format; 7 8 import capstone.api; 9 import capstone.capstone; 10 import capstone.internal; 11 import capstone.instruction; 12 import capstone.error; 13 14 /// An extended `InstructionRange` that provides architecture-specific instructions 15 class InstructionImplRange(TInstruction) : InstructionRange { 16 import core.exception: RangeError; 17 private{ 18 const Capstone cs; 19 const ubyte[] code; // Keep ref, s.t. it cannot be deallocated externally 20 const(ubyte)* pCode; 21 ulong codeLength; 22 ulong address; 23 24 TInstruction instr; 25 cs_insn* pInsn; 26 27 bool hasFront; 28 } 29 30 package this(in Capstone cs, in ubyte[] code, in ulong address){ 31 this.cs = cs; 32 this.code = code; 33 this.pCode = code.ptr; 34 this.codeLength = code.length; 35 this.address = address; 36 this.hasFront = true; 37 38 popFront; 39 } 40 41 /// True if no disassemblable instructions remain 42 override bool empty() const {return !hasFront;} 43 44 /** The latest disassembled instruction 45 46 Throws if called on an `empty` range. 47 */ 48 override TInstruction front() { 49 enforce!RangeError(!empty, "Trying to access an empty range (%s)".format(typeof(this).stringof)); 50 return instr; 51 } 52 53 /** Advances the range, disassembling the next instruction 54 55 Throws if called on an `empty` range. 56 */ 57 override void popFront(){ 58 enforce!RangeError(!empty, "Trying to access an empty range (%s)".format(typeof(this).stringof)); 59 pInsn = cs_malloc(cs.handle); // Is freed by Instruction 60 if(!pInsn) 61 throw new CapstoneException("Insufficient memory to allocate an instruction", ErrorCode.OutOfMemory); 62 hasFront = cs_disasm_iter(cs.handle, &pCode, &codeLength, &address, pInsn); 63 if(hasFront) 64 instr = new TInstruction(cs, pInsn); // Instruction takes ownership of pointer 65 else 66 cs_errno(cs.handle).checkErrno; 67 } 68 } 69 static assert(isInputRange!(InstructionRange));