/src/capstonenext/MCInst.c
Line  | Count  | Source  | 
1  |  | /* Capstone Disassembly Engine */  | 
2  |  | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */  | 
3  |  | #if defined(CAPSTONE_HAS_OSXKERNEL)  | 
4  |  | #include <Availability.h>  | 
5  |  | #include <libkern/libkern.h>  | 
6  |  | #else  | 
7  |  | #include <stdio.h>  | 
8  |  | #include <stdlib.h>  | 
9  |  | #endif  | 
10  |  | #include <string.h>  | 
11  |  | #include <assert.h>  | 
12  |  |  | 
13  |  | #include "MCInstrDesc.h"  | 
14  |  | #include "MCInst.h"  | 
15  |  | #include "utils.h"  | 
16  |  |  | 
17  | 2.92M  | #define MCINST_CACHE (ARR_SIZE(mcInst->Operands) - 1)  | 
18  |  |  | 
19  |  | void MCInst_Init(MCInst *inst, cs_arch arch)  | 
20  | 3.39M  | { | 
21  | 3.39M  |   memset(inst, 0, sizeof(MCInst));  | 
22  |  |   // unnecessary to initialize in loop . its expensive and inst->size should be honored  | 
23  | 3.39M  |   inst->Operands[0].Kind = kInvalid;  | 
24  | 3.39M  |   inst->Operands[0].ImmVal = 0;  | 
25  |  |  | 
26  | 3.39M  |   inst->Opcode = 0;  | 
27  | 3.39M  |   inst->OpcodePub = 0;  | 
28  | 3.39M  |   inst->size = 0;  | 
29  | 3.39M  |   inst->has_imm = false;  | 
30  | 3.39M  |   inst->op1_size = 0;  | 
31  | 3.39M  |   inst->ac_idx = 0;  | 
32  | 3.39M  |   inst->popcode_adjust = 0;  | 
33  | 3.39M  |   inst->assembly[0] = '\0';  | 
34  | 3.39M  |   inst->wasm_data.type = WASM_OP_INVALID;  | 
35  | 3.39M  |   inst->xAcquireRelease = 0;  | 
36  | 166M  |   for (int i = 0; i < MAX_MC_OPS; ++i)  | 
37  | 162M  |     inst->tied_op_idx[i] = -1;  | 
38  | 3.39M  |   inst->isAliasInstr = false;  | 
39  | 3.39M  |   inst->fillDetailOps = false;  | 
40  | 3.39M  |   memset(&inst->hppa_ext, 0, sizeof(inst->hppa_ext));  | 
41  |  |  | 
42  |  |   // Set default assembly dialect.  | 
43  | 3.39M  |   switch (arch) { | 
44  | 3.22M  |   default:  | 
45  | 3.22M  |     break;  | 
46  | 3.22M  |   case CS_ARCH_SYSTEMZ:  | 
47  | 169k  |     inst->MAI.assemblerDialect = SYSTEMZASMDIALECT_AD_HLASM;  | 
48  | 169k  |     break;  | 
49  | 3.39M  |   }  | 
50  | 3.39M  | }  | 
51  |  |  | 
52  |  | void MCInst_clear(MCInst *inst)  | 
53  | 6.90M  | { | 
54  | 6.90M  |   inst->size = 0;  | 
55  | 6.90M  | }  | 
56  |  |  | 
57  |  | // does not free @Op  | 
58  |  | void MCInst_insert0(MCInst *inst, int index, MCOperand *Op)  | 
59  | 1.85M  | { | 
60  | 1.85M  |   CS_ASSERT_RET(index < MAX_MC_OPS);  | 
61  | 1.85M  |   int i;  | 
62  |  |  | 
63  | 3.23M  |   for (i = inst->size; i > index; i--)  | 
64  |  |     //memcpy(&(inst->Operands[i]), &(inst->Operands[i-1]), sizeof(MCOperand));  | 
65  | 1.37M  |     inst->Operands[i] = inst->Operands[i - 1];  | 
66  |  |  | 
67  | 1.85M  |   inst->Operands[index] = *Op;  | 
68  | 1.85M  |   inst->size++;  | 
69  | 1.85M  | }  | 
70  |  |  | 
71  |  | void MCInst_setOpcode(MCInst *inst, unsigned Op)  | 
72  | 6.35M  | { | 
73  | 6.35M  |   inst->Opcode = Op;  | 
74  | 6.35M  | }  | 
75  |  |  | 
76  |  | void MCInst_setOpcodePub(MCInst *inst, unsigned Op)  | 
77  | 235k  | { | 
78  | 235k  |   inst->OpcodePub = Op;  | 
79  | 235k  | }  | 
80  |  |  | 
81  |  | unsigned MCInst_getOpcode(const MCInst *inst)  | 
82  | 49.4M  | { | 
83  | 49.4M  |   return inst->Opcode;  | 
84  | 49.4M  | }  | 
85  |  |  | 
86  |  | unsigned MCInst_getOpcodePub(const MCInst *inst)  | 
87  | 6.59M  | { | 
88  | 6.59M  |   return inst->OpcodePub;  | 
89  | 6.59M  | }  | 
90  |  |  | 
91  |  | MCOperand *MCInst_getOperand(MCInst *inst, unsigned i)  | 
92  | 36.5M  | { | 
93  | 36.5M  |   assert(i < MAX_MC_OPS);  | 
94  | 36.5M  |   return &inst->Operands[i];  | 
95  | 36.5M  | }  | 
96  |  |  | 
97  |  | unsigned MCInst_getNumOperands(const MCInst *inst)  | 
98  | 13.0M  | { | 
99  | 13.0M  |   return inst->size;  | 
100  | 13.0M  | }  | 
101  |  |  | 
102  |  | // This addOperand2 function doesn't free Op  | 
103  |  | void MCInst_addOperand2(MCInst *inst, MCOperand *Op)  | 
104  | 1.93k  | { | 
105  | 1.93k  |   CS_ASSERT_RET(inst->size < MAX_MC_OPS);  | 
106  | 1.93k  |   inst->Operands[inst->size] = *Op;  | 
107  |  |  | 
108  | 1.93k  |   inst->size++;  | 
109  | 1.93k  | }  | 
110  |  |  | 
111  |  | bool MCOperand_isValid(const MCOperand *op)  | 
112  | 0  | { | 
113  | 0  |   return op->Kind != kInvalid;  | 
114  | 0  | }  | 
115  |  |  | 
116  |  | bool MCOperand_isReg(const MCOperand *op)  | 
117  | 11.9M  | { | 
118  | 11.9M  |   return op->Kind == kRegister || op->MachineOperandType == kRegister;  | 
119  | 11.9M  | }  | 
120  |  |  | 
121  |  | bool MCOperand_isImm(const MCOperand *op)  | 
122  | 3.55M  | { | 
123  | 3.55M  |   return op->Kind == kImmediate || op->MachineOperandType == kImmediate;  | 
124  | 3.55M  | }  | 
125  |  |  | 
126  |  | bool MCOperand_isFPImm(const MCOperand *op)  | 
127  | 1.73k  | { | 
128  | 1.73k  |   return op->Kind == kFPImmediate;  | 
129  | 1.73k  | }  | 
130  |  |  | 
131  |  | bool MCOperand_isDFPImm(const MCOperand *op)  | 
132  | 1.18k  | { | 
133  | 1.18k  |   return op->Kind == kDFPImmediate;  | 
134  | 1.18k  | }  | 
135  |  |  | 
136  |  | bool MCOperand_isExpr(const MCOperand *op)  | 
137  | 171k  | { | 
138  | 171k  |   return op->Kind == kExpr;  | 
139  | 171k  | }  | 
140  |  |  | 
141  |  | bool MCOperand_isInst(const MCOperand *op)  | 
142  | 0  | { | 
143  | 0  |   return op->Kind == kInst;  | 
144  | 0  | }  | 
145  |  |  | 
146  |  | /// getReg - Returns the register number.  | 
147  |  | unsigned MCOperand_getReg(const MCOperand *op)  | 
148  | 22.8M  | { | 
149  | 22.8M  |   return op->RegVal;  | 
150  | 22.8M  | }  | 
151  |  |  | 
152  |  | /// setReg - Set the register number.  | 
153  |  | void MCOperand_setReg(MCOperand *op, unsigned Reg)  | 
154  | 27.5k  | { | 
155  | 27.5k  |   op->RegVal = Reg;  | 
156  | 27.5k  | }  | 
157  |  |  | 
158  |  | int64_t MCOperand_getImm(const MCOperand *op)  | 
159  | 11.9M  | { | 
160  | 11.9M  |   return op->ImmVal;  | 
161  | 11.9M  | }  | 
162  |  |  | 
163  |  | int64_t MCOperand_getExpr(const MCOperand *op)  | 
164  | 0  | { | 
165  | 0  |   return op->ImmVal;  | 
166  | 0  | }  | 
167  |  |  | 
168  |  | void MCOperand_setImm(MCOperand *op, int64_t Val)  | 
169  | 37.4k  | { | 
170  | 37.4k  |   op->ImmVal = Val;  | 
171  | 37.4k  | }  | 
172  |  |  | 
173  |  | double MCOperand_getFPImm(const MCOperand *op)  | 
174  | 0  | { | 
175  | 0  |   return op->FPImmVal;  | 
176  | 0  | }  | 
177  |  |  | 
178  |  | void MCOperand_setFPImm(MCOperand *op, double Val)  | 
179  | 0  | { | 
180  | 0  |   op->FPImmVal = Val;  | 
181  | 0  | }  | 
182  |  |  | 
183  |  | MCOperand *MCOperand_CreateReg1(MCInst *mcInst, unsigned Reg)  | 
184  | 1.67M  | { | 
185  | 1.67M  |   MCOperand *op = &(mcInst->Operands[MCINST_CACHE]);  | 
186  |  |  | 
187  | 1.67M  |   op->MachineOperandType = kRegister;  | 
188  | 1.67M  |   op->Kind = kRegister;  | 
189  | 1.67M  |   op->RegVal = Reg;  | 
190  |  |  | 
191  | 1.67M  |   return op;  | 
192  | 1.67M  | }  | 
193  |  |  | 
194  |  | void MCOperand_CreateReg0(MCInst *mcInst, unsigned Reg)  | 
195  | 12.4M  | { | 
196  | 12.4M  |   MCOperand *op = &(mcInst->Operands[mcInst->size]);  | 
197  | 12.4M  |   mcInst->size++;  | 
198  |  |  | 
199  | 12.4M  |   op->MachineOperandType = kRegister;  | 
200  | 12.4M  |   op->Kind = kRegister;  | 
201  | 12.4M  |   op->RegVal = Reg;  | 
202  | 12.4M  | }  | 
203  |  |  | 
204  |  | MCOperand *MCOperand_CreateImm1(MCInst *mcInst, int64_t Val)  | 
205  | 1.25M  | { | 
206  | 1.25M  |   MCOperand *op = &(mcInst->Operands[MCINST_CACHE]);  | 
207  |  |  | 
208  | 1.25M  |   op->MachineOperandType = kImmediate;  | 
209  | 1.25M  |   op->Kind = kImmediate;  | 
210  | 1.25M  |   op->ImmVal = Val;  | 
211  |  |  | 
212  | 1.25M  |   return op;  | 
213  | 1.25M  | }  | 
214  |  |  | 
215  |  | void MCOperand_CreateImm0(MCInst *mcInst, int64_t Val)  | 
216  | 5.63M  | { | 
217  | 5.63M  |   assert(mcInst->size < MAX_MC_OPS);  | 
218  | 5.63M  |   MCOperand *op = &(mcInst->Operands[mcInst->size]);  | 
219  | 5.63M  |   mcInst->size++;  | 
220  |  |  | 
221  | 5.63M  |   op->MachineOperandType = kImmediate;  | 
222  | 5.63M  |   op->Kind = kImmediate;  | 
223  | 5.63M  |   op->ImmVal = Val;  | 
224  | 5.63M  | }  | 
225  |  |  | 
226  |  | /// Check if any operand of the MCInstrDesc is predicable  | 
227  |  | bool MCInst_isPredicable(const MCInstrDesc *MIDesc)  | 
228  | 922k  | { | 
229  | 922k  |   const MCOperandInfo *OpInfo = MIDesc->OpInfo;  | 
230  | 922k  |   unsigned NumOps = MIDesc->NumOperands;  | 
231  | 4.16M  |   for (unsigned i = 0; i < NumOps; ++i) { | 
232  | 4.09M  |     if (MCOperandInfo_isPredicate(&OpInfo[i])) { | 
233  | 854k  |       return true;  | 
234  | 854k  |     }  | 
235  | 4.09M  |   }  | 
236  | 68.8k  |   return false;  | 
237  | 922k  | }  | 
238  |  |  | 
239  |  | /// Checks if tied operands exist in the instruction and sets  | 
240  |  | /// - The writeback flag in detail  | 
241  |  | /// - Saves the indices of the tied destination operands.  | 
242  |  | void MCInst_handleWriteback(MCInst *MI, const MCInstrDesc *InstDescTable,  | 
243  |  |           unsigned tbl_size)  | 
244  | 1.44M  | { | 
245  | 1.44M  |   const MCInstrDesc *InstDesc = NULL;  | 
246  | 1.44M  |   const MCOperandInfo *OpInfo = NULL;  | 
247  | 1.44M  |   unsigned short NumOps = 0;  | 
248  | 1.44M  |   InstDesc =  | 
249  | 1.44M  |     MCInstrDesc_get(MCInst_getOpcode(MI), InstDescTable, tbl_size);  | 
250  | 1.44M  |   OpInfo = InstDesc->OpInfo;  | 
251  | 1.44M  |   NumOps = InstDesc->NumOperands;  | 
252  |  |  | 
253  | 8.23M  |   for (unsigned i = 0; i < NumOps; ++i) { | 
254  | 6.78M  |     if (MCOperandInfo_isTiedToOp(&OpInfo[i])) { | 
255  | 356k  |       int idx = MCOperandInfo_getOperandConstraint(  | 
256  | 356k  |         InstDesc, i, MCOI_TIED_TO);  | 
257  |  |  | 
258  | 356k  |       if (idx == -1)  | 
259  | 0  |         continue;  | 
260  |  |  | 
261  | 356k  |       if (i >= MAX_MC_OPS) { | 
262  | 0  |         assert(0 &&  | 
263  | 0  |                "Maximum number of MC operands reached.");  | 
264  | 0  |       }  | 
265  | 356k  |       MI->tied_op_idx[i] = idx;  | 
266  |  |  | 
267  | 356k  |       if (MI->flat_insn->detail)  | 
268  | 356k  |         MI->flat_insn->detail->writeback = true;  | 
269  | 356k  |     }  | 
270  | 6.78M  |   }  | 
271  | 1.44M  | }  | 
272  |  |  | 
273  |  | /// Check if operand with OpNum is tied by another operand  | 
274  |  | /// (operand is tying destination).  | 
275  |  | bool MCInst_opIsTied(const MCInst *MI, unsigned OpNum)  | 
276  | 6.09M  | { | 
277  | 6.09M  |   assert(OpNum < MAX_MC_OPS && "Maximum number of MC operands exceeded.");  | 
278  | 287M  |   for (int i = 0; i < MAX_MC_OPS; ++i) { | 
279  | 281M  |     if (MI->tied_op_idx[i] == OpNum)  | 
280  | 247k  |       return true;  | 
281  | 281M  |   }  | 
282  | 5.85M  |   return false;  | 
283  | 6.09M  | }  | 
284  |  |  | 
285  |  | /// Check if operand with OpNum is tying another operand  | 
286  |  | /// (operand is tying src).  | 
287  |  | bool MCInst_opIsTying(const MCInst *MI, unsigned OpNum)  | 
288  | 6.10M  | { | 
289  | 6.10M  |   assert(OpNum < MAX_MC_OPS && "Maximum number of MC operands exceeded.");  | 
290  | 6.10M  |   return MI->tied_op_idx[OpNum] != -1;  | 
291  | 6.10M  | }  | 
292  |  |  | 
293  |  | /// Returns the value of the @MCInst operand at index @OpNum.  | 
294  |  | uint64_t MCInst_getOpVal(MCInst *MI, unsigned OpNum)  | 
295  | 5.85M  | { | 
296  | 5.85M  |   assert(OpNum < MAX_MC_OPS);  | 
297  | 5.85M  |   MCOperand *op = MCInst_getOperand(MI, OpNum);  | 
298  | 5.85M  |   if (MCOperand_isReg(op))  | 
299  | 4.21M  |     return MCOperand_getReg(op);  | 
300  | 1.64M  |   else if (MCOperand_isImm(op))  | 
301  | 1.64M  |     return MCOperand_getImm(op);  | 
302  | 0  |   else  | 
303  | 1.64M  |     assert(0 && "Operand type not handled in this getter.");  | 
304  | 0  |   return MCOperand_getImm(op);  | 
305  | 5.85M  | }  | 
306  |  |  | 
307  |  | void MCInst_setIsAlias(MCInst *MI, bool Flag)  | 
308  | 1.54M  | { | 
309  | 1.54M  |   assert(MI);  | 
310  | 1.54M  |   MI->isAliasInstr = Flag;  | 
311  | 1.54M  |   MI->flat_insn->is_alias = Flag;  | 
312  | 1.54M  | }  | 
313  |  |  | 
314  |  | /// @brief Copies the relevant members of a temporary MCInst to  | 
315  |  | /// the main MCInst. This is used if TryDecode was run on a temporary MCInst.  | 
316  |  | /// @param MI The main MCInst  | 
317  |  | /// @param TmpMI The temporary MCInst.  | 
318  |  | void MCInst_updateWithTmpMI(MCInst *MI, MCInst *TmpMI)  | 
319  | 0  | { | 
320  | 0  |   MI->size = TmpMI->size;  | 
321  | 0  |   MI->Opcode = TmpMI->Opcode;  | 
322  | 0  |   assert(MI->size < MAX_MC_OPS);  | 
323  | 0  |   memcpy(MI->Operands, TmpMI->Operands,  | 
324  | 0  |          sizeof(MI->Operands[0]) * MI->size);  | 
325  | 0  | }  | 
326  |  |  | 
327  |  | /// @brief Sets the softfail/illegal flag in the cs_insn.  | 
328  |  | /// Setting it indicates the instruction can be decoded, but is invalid  | 
329  |  | /// due to not allowed operands or an illegal context.  | 
330  |  | ///  | 
331  |  | /// @param MI The MCInst holding the cs_insn currently decoded.  | 
332  |  | void MCInst_setSoftFail(MCInst *MI)  | 
333  | 111k  | { | 
334  | 111k  |   assert(MI && MI->flat_insn);  | 
335  | 111k  |   MI->flat_insn->illegal = true;  | 
336  | 111k  | }  |