/src/capstonenext/MCInst.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine */ |
2 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2019 */ |
3 | | |
4 | | #if defined(CAPSTONE_HAS_OSXKERNEL) |
5 | | #include <Availability.h> |
6 | | #include <libkern/libkern.h> |
7 | | #else |
8 | | #include <stdio.h> |
9 | | #include <stdlib.h> |
10 | | #endif |
11 | | #include <string.h> |
12 | | #include <assert.h> |
13 | | |
14 | | #include "MCInst.h" |
15 | | #include "utils.h" |
16 | | |
17 | 3.60M | #define MCINST_CACHE (ARR_SIZE(mcInst->Operands) - 1) |
18 | | |
19 | | void MCInst_Init(MCInst *inst) |
20 | 6.56M | { |
21 | | // unnecessary to initialize in loop . its expensive and inst->size shuold be honored |
22 | 6.56M | inst->Operands[0].Kind = kInvalid; |
23 | 6.56M | inst->Operands[0].ImmVal = 0; |
24 | | |
25 | 6.56M | inst->Opcode = 0; |
26 | 6.56M | inst->OpcodePub = 0; |
27 | 6.56M | inst->size = 0; |
28 | 6.56M | inst->has_imm = false; |
29 | 6.56M | inst->op1_size = 0; |
30 | 6.56M | inst->ac_idx = 0; |
31 | 6.56M | inst->popcode_adjust = 0; |
32 | 6.56M | inst->assembly[0] = '\0'; |
33 | 6.56M | inst->wasm_data.type = WASM_OP_INVALID; |
34 | 6.56M | inst->xAcquireRelease = 0; |
35 | 321M | for (int i = 0; i < MAX_MC_OPS; ++i) |
36 | 315M | inst->tied_op_idx[i] = -1; |
37 | 6.56M | inst->isAliasInstr = false; |
38 | 6.56M | inst->fillDetailOps = false; |
39 | 6.56M | } |
40 | | |
41 | | void MCInst_clear(MCInst *inst) |
42 | 6.91M | { |
43 | 6.91M | inst->size = 0; |
44 | 6.91M | } |
45 | | |
46 | | // does not free @Op |
47 | | void MCInst_insert0(MCInst *inst, int index, MCOperand *Op) |
48 | 3.61M | { |
49 | 3.61M | assert(index < MAX_MC_OPS); |
50 | 3.61M | int i; |
51 | | |
52 | 6.19M | for(i = inst->size; i > index; i--) |
53 | | //memcpy(&(inst->Operands[i]), &(inst->Operands[i-1]), sizeof(MCOperand)); |
54 | 2.57M | inst->Operands[i] = inst->Operands[i-1]; |
55 | | |
56 | 3.61M | inst->Operands[index] = *Op; |
57 | 3.61M | inst->size++; |
58 | 3.61M | } |
59 | | |
60 | | void MCInst_setOpcode(MCInst *inst, unsigned Op) |
61 | 6.57M | { |
62 | 6.57M | inst->Opcode = Op; |
63 | 6.57M | } |
64 | | |
65 | | void MCInst_setOpcodePub(MCInst *inst, unsigned Op) |
66 | 185k | { |
67 | 185k | inst->OpcodePub = Op; |
68 | 185k | } |
69 | | |
70 | | unsigned MCInst_getOpcode(const MCInst *inst) |
71 | 49.5M | { |
72 | 49.5M | return inst->Opcode; |
73 | 49.5M | } |
74 | | |
75 | | unsigned MCInst_getOpcodePub(const MCInst *inst) |
76 | 6.80M | { |
77 | 6.80M | return inst->OpcodePub; |
78 | 6.80M | } |
79 | | |
80 | | MCOperand *MCInst_getOperand(MCInst *inst, unsigned i) |
81 | 31.2M | { |
82 | 31.2M | assert(i < MAX_MC_OPS); |
83 | 31.2M | return &inst->Operands[i]; |
84 | 31.2M | } |
85 | | |
86 | | unsigned MCInst_getNumOperands(const MCInst *inst) |
87 | 13.4M | { |
88 | 13.4M | return inst->size; |
89 | 13.4M | } |
90 | | |
91 | | // This addOperand2 function doesnt free Op |
92 | | void MCInst_addOperand2(MCInst *inst, MCOperand *Op) |
93 | 1.85k | { |
94 | 1.85k | assert(inst->size < MAX_MC_OPS); |
95 | 1.85k | inst->Operands[inst->size] = *Op; |
96 | | |
97 | 1.85k | inst->size++; |
98 | 1.85k | } |
99 | | |
100 | | bool MCOperand_isValid(const MCOperand *op) |
101 | 0 | { |
102 | 0 | return op->Kind != kInvalid; |
103 | 0 | } |
104 | | |
105 | | bool MCOperand_isReg(const MCOperand *op) |
106 | 14.7M | { |
107 | 14.7M | return op->Kind == kRegister; |
108 | 14.7M | } |
109 | | |
110 | | bool MCOperand_isImm(const MCOperand *op) |
111 | 4.90M | { |
112 | 4.90M | return op->Kind == kImmediate; |
113 | 4.90M | } |
114 | | |
115 | | bool MCOperand_isFPImm(const MCOperand *op) |
116 | 585 | { |
117 | 585 | return op->Kind == kFPImmediate; |
118 | 585 | } |
119 | | |
120 | | bool MCOperand_isDFPImm(const MCOperand *op) |
121 | 2.76k | { |
122 | 2.76k | return op->Kind == kDFPImmediate; |
123 | 2.76k | } |
124 | | |
125 | | bool MCOperand_isExpr(const MCOperand *op) |
126 | 99.7k | { |
127 | 99.7k | return op->Kind == kExpr; |
128 | 99.7k | } |
129 | | |
130 | | bool MCOperand_isInst(const MCOperand *op) |
131 | 0 | { |
132 | 0 | return op->Kind == kInst; |
133 | 0 | } |
134 | | |
135 | | /// getReg - Returns the register number. |
136 | | unsigned MCOperand_getReg(const MCOperand *op) |
137 | 21.5M | { |
138 | 21.5M | return op->RegVal; |
139 | 21.5M | } |
140 | | |
141 | | /// setReg - Set the register number. |
142 | | void MCOperand_setReg(MCOperand *op, unsigned Reg) |
143 | 22.1k | { |
144 | 22.1k | op->RegVal = Reg; |
145 | 22.1k | } |
146 | | |
147 | | int64_t MCOperand_getImm(const MCOperand *op) |
148 | 10.8M | { |
149 | 10.8M | return op->ImmVal; |
150 | 10.8M | } |
151 | | |
152 | | void MCOperand_setImm(MCOperand *op, int64_t Val) |
153 | 30.4k | { |
154 | 30.4k | op->ImmVal = Val; |
155 | 30.4k | } |
156 | | |
157 | | double MCOperand_getFPImm(const MCOperand *op) |
158 | 0 | { |
159 | 0 | return op->FPImmVal; |
160 | 0 | } |
161 | | |
162 | | void MCOperand_setFPImm(MCOperand *op, double Val) |
163 | 0 | { |
164 | 0 | op->FPImmVal = Val; |
165 | 0 | } |
166 | | |
167 | | MCOperand *MCOperand_CreateReg1(MCInst *mcInst, unsigned Reg) |
168 | 2.05M | { |
169 | 2.05M | MCOperand *op = &(mcInst->Operands[MCINST_CACHE]); |
170 | | |
171 | 2.05M | op->MachineOperandType = kRegister; |
172 | 2.05M | op->Kind = kRegister; |
173 | 2.05M | op->RegVal = Reg; |
174 | | |
175 | 2.05M | return op; |
176 | 2.05M | } |
177 | | |
178 | | void MCOperand_CreateReg0(MCInst *mcInst, unsigned Reg) |
179 | 12.2M | { |
180 | 12.2M | MCOperand *op = &(mcInst->Operands[mcInst->size]); |
181 | 12.2M | mcInst->size++; |
182 | | |
183 | 12.2M | op->MachineOperandType = kRegister; |
184 | 12.2M | op->Kind = kRegister; |
185 | 12.2M | op->RegVal = Reg; |
186 | 12.2M | } |
187 | | |
188 | | MCOperand *MCOperand_CreateImm1(MCInst *mcInst, int64_t Val) |
189 | 1.54M | { |
190 | 1.54M | MCOperand *op = &(mcInst->Operands[MCINST_CACHE]); |
191 | | |
192 | 1.54M | op->MachineOperandType = kImmediate; |
193 | 1.54M | op->Kind = kImmediate; |
194 | 1.54M | op->ImmVal = Val; |
195 | | |
196 | 1.54M | return op; |
197 | 1.54M | } |
198 | | |
199 | | void MCOperand_CreateImm0(MCInst *mcInst, int64_t Val) |
200 | 5.70M | { |
201 | 5.70M | assert(mcInst->size < MAX_MC_OPS); |
202 | 5.70M | MCOperand *op = &(mcInst->Operands[mcInst->size]); |
203 | 5.70M | mcInst->size++; |
204 | | |
205 | 5.70M | op->MachineOperandType = kImmediate; |
206 | 5.70M | op->Kind = kImmediate; |
207 | 5.70M | op->ImmVal = Val; |
208 | 5.70M | } |
209 | | |
210 | | /// Check if any operand of the MCInstrDesc is predicable |
211 | | bool MCInst_isPredicable(const MCInstrDesc *MIDesc) |
212 | 1.02M | { |
213 | 1.02M | const MCOperandInfo *OpInfo = MIDesc->OpInfo; |
214 | 1.02M | unsigned NumOps = MIDesc->NumOperands; |
215 | 4.47M | for (unsigned i = 0; i < NumOps; ++i) { |
216 | 4.41M | if (MCOperandInfo_isPredicate(&OpInfo[i])) { |
217 | 964k | return true; |
218 | 964k | } |
219 | 4.41M | } |
220 | 58.6k | return false; |
221 | 1.02M | } |
222 | | |
223 | | /// Checks if tied operands exist in the instruction and sets |
224 | | /// - The writeback flag in detail |
225 | | /// - Saves the indices of the tied destination operands. |
226 | | void MCInst_handleWriteback(MCInst *MI, const MCInstrDesc *InstDesc) |
227 | 1.39M | { |
228 | 1.39M | const MCOperandInfo *OpInfo = InstDesc[MCInst_getOpcode(MI)].OpInfo; |
229 | 1.39M | unsigned short NumOps = InstDesc[MCInst_getOpcode(MI)].NumOperands; |
230 | | |
231 | 1.39M | unsigned i; |
232 | 7.96M | for (i = 0; i < NumOps; ++i) { |
233 | 6.56M | if (MCOperandInfo_isTiedToOp(&OpInfo[i])) { |
234 | 292k | int idx = MCOperandInfo_getOperandConstraint( |
235 | 292k | &InstDesc[MCInst_getOpcode(MI)], i, |
236 | 292k | MCOI_TIED_TO); |
237 | | |
238 | 292k | if (idx == -1) |
239 | 0 | continue; |
240 | | |
241 | 292k | if (i >= MAX_MC_OPS) { |
242 | 0 | assert(0 && |
243 | 0 | "Maximum number of MC operands reached."); |
244 | 0 | } |
245 | 292k | MI->tied_op_idx[i] = idx; |
246 | | |
247 | 292k | if (MI->flat_insn->detail) |
248 | 292k | MI->flat_insn->detail->writeback = true; |
249 | 292k | } |
250 | 6.56M | } |
251 | 1.39M | } |
252 | | |
253 | | /// Check if operand with OpNum is tied by another operand |
254 | | /// (operand is tying destination). |
255 | | bool MCInst_opIsTied(const MCInst *MI, unsigned OpNum) |
256 | 4.49M | { |
257 | 4.49M | assert(OpNum < MAX_MC_OPS && "Maximum number of MC operands exceeded."); |
258 | 211M | for (int i = 0; i < MAX_MC_OPS; ++i) { |
259 | 206M | if (MI->tied_op_idx[i] == OpNum) |
260 | 198k | return true; |
261 | 206M | } |
262 | 4.29M | return false; |
263 | 4.49M | } |
264 | | |
265 | | /// Check if operand with OpNum is tying another operand |
266 | | /// (operand is tying src). |
267 | | bool MCInst_opIsTying(const MCInst *MI, unsigned OpNum) |
268 | 4.44M | { |
269 | 4.44M | assert(OpNum < MAX_MC_OPS && "Maximum number of MC operands exceeded."); |
270 | 4.44M | return MI->tied_op_idx[OpNum] != -1; |
271 | 4.44M | } |
272 | | |
273 | | /// Returns the value of the @MCInst operand at index @OpNum. |
274 | | uint64_t MCInst_getOpVal(MCInst *MI, unsigned OpNum) |
275 | 4.33M | { |
276 | 4.33M | assert(OpNum < MAX_MC_OPS); |
277 | 4.33M | MCOperand *op = MCInst_getOperand(MI, OpNum); |
278 | 4.33M | if (MCOperand_isReg(op)) |
279 | 3.07M | return MCOperand_getReg(op); |
280 | 1.26M | else if (MCOperand_isImm(op)) |
281 | 1.26M | return MCOperand_getImm(op); |
282 | 0 | else |
283 | 0 | assert(0 && "Operand type not handled in this getter."); |
284 | 0 | return MCOperand_getImm(op); |
285 | 4.33M | } |
286 | | |
287 | 1.43M | void MCInst_setIsAlias(MCInst *MI, bool Flag) { |
288 | 1.43M | assert(MI); |
289 | 1.43M | MI->isAliasInstr = Flag; |
290 | 1.43M | MI->flat_insn->is_alias = Flag; |
291 | 1.43M | } |
292 | | |
293 | | /// @brief Copies the relevant members of a temporary MCInst to |
294 | | /// the main MCInst. This is used if TryDecode was run on a temporary MCInst. |
295 | | /// @param MI The main MCInst |
296 | | /// @param TmpMI The temporary MCInst. |
297 | 344 | void MCInst_updateWithTmpMI(MCInst *MI, MCInst *TmpMI) { |
298 | 344 | MI->size = TmpMI->size; |
299 | 344 | MI->Opcode = TmpMI->Opcode; |
300 | 344 | assert(MI->size < MAX_MC_OPS); |
301 | 344 | memcpy(MI->Operands, TmpMI->Operands, sizeof(MI->Operands[0]) * MI->size); |
302 | 344 | } |