1 /// Object-oriented wrapper of disassembled instructions
2 module capstone.instruction;
3 
4 import std.conv: to;
5 import std.typecons: Nullable;
6 import std.algorithm: canFind;
7 
8 import capstone.api;
9 import capstone.capstone;
10 import capstone.detail;
11 import capstone.error;
12 import capstone.internal;
13 import capstone.instructiongroup;
14 import capstone.register;
15 
16 /// Architecture-independent instruction base class
17 abstract class Instruction {
18 private:
19     const Capstone cs;
20     cs_insn* internal; // Have to keep it around for cs_regs_access
21 
22 public:
23 	/// Address (EIP) of this instruction
24     auto address() const {return internal.address;}
25 	/// Machine bytes of this instruction
26     auto bytes() const {return internal.bytes[0..internal.size];}
27 	/// Ascii text of instruction mnemonic
28     auto mnemonic() const {return internal.mnemonic.ptr.to!string;}
29 	/// Ascii text of instruction operands
30     auto opStr() const {return internal.op_str.ptr.to!string;}
31 	
32     private this(in Capstone cs, cs_insn* internal){
33         this.cs = cs;
34         this.internal = internal;
35     }
36 
37     ~this(){
38         assert(internal);
39         cs_free(internal, 1);
40     }
41 
42     /// Retrieves instruction's id as plain integer
43     auto idAsInt() const {return internal.id;}
44 
45     /** Returns friendly string representation of an instruction's name
46     
47     When in diet mode, this API is irrelevant because engine does not store instruction names.
48     */
49     string name() const {
50         if(diet)
51             throw new CapstoneException("Instruction names are not stored when running Capstone in diet mode",
52                 ErrorCode.IrrelevantDataAccessInDietEngine);
53         return cs_insn_name(cs.handle, internal.id).to!string; // TODO: Error handling
54     }
55 
56     /** More details about the instruction
57     
58     Note that this is only available if both requirements are met: 
59     $(OL
60         $(LI details are enabled)
61         $(LI the engine is not in Skipdata mode))
62     */ 
63     const(Detail) detail() const;
64 
65     /// Checks whether the instruction belongs to the instruction group `group`
66     bool isInGroup(in InstructionGroup group) const {
67         return cs_insn_group(cs.handle, internal, group._id); // TODO: Error handling
68     }
69 
70     /// Checks if the instruction IMPLICITLY uses a particular register
71     bool reads(in Register reg) const {
72         return cs_reg_read(cs.handle, internal, reg._id); // TODO: Error handling
73     }
74 
75     /// Checks if the instruction IMPLICITLY modifies a particular register
76     bool writes(in Register reg) const {
77         return cs_reg_write(cs.handle, internal, reg._id); // TODO: Error handling
78     }
79 
80     /// Retrieves both the implicitly and explicitly written registers
81     const(Register)[] writes() const;
82 
83     /// Retrieves both the implicitly and explicitly read registers
84     const(Register)[] reads() const;
85 }
86 
87 /** Class template for architecture-specific instructions
88 
89 Note that all architecture-specific instances, like `X86Instruction`, instantiate and derive from this one.
90 */
91 abstract class InstructionImpl(TId, TRegister, TDetail) : Instruction if(is(TId == enum)) { // TODO: isRegister, isDetail
92     private Nullable!TDetail _detail;
93 
94     package this(in Capstone cs, cs_insn* internal){
95         super(cs, internal);
96         if(cs.detail && !cs.skipData)
97             _detail = new TDetail(cs, internal.detail);
98     }
99 
100 	/// Retrieves instruction's id
101     auto id() const {return internal.id.to!TId;}
102 
103     override const(TDetail) detail() const {
104         if(_detail.isNull)
105             throw new CapstoneException("Trying to access unavailable instruction detail", ErrorCode.UnavailableInstructionDetail);
106         return _detail.get;
107     }
108 
109     private const(TRegister)[] accessedRegs(in bool writeAccess) const {
110         import std.algorithm: map;
111         import std.array: array;
112 
113         if(diet)
114             throw new CapstoneException("Registers accessed by an instruction are not stored when running Capstone in diet mode",
115                 ErrorCode.IrrelevantDataAccessInDietEngine);
116         cs_regs read, write;
117         ubyte numRead, numWrite;
118         cs_regs_access(cs.handle, internal, &read, &numRead, &write, &numWrite).checkErrno;
119         auto regs = writeAccess ? write[0..numWrite] : read[0..numRead];
120         return regs.map!(reg => new TRegister(cs, reg)).array;
121     }
122 
123     override const(TRegister)[] writes() const {return accessedRegs(true);}
124     override const(TRegister)[] reads() const {return accessedRegs(false);}
125 }