/src/capstonenext/arch/Sparc/SparcInstPrinter.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Capstone Disassembly Engine, http://www.capstone-engine.org */ |
2 | | /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2022, */ |
3 | | /* Rot127 <unisono@quyllur.org> 2022-2023 */ |
4 | | /* Automatically translated source file from LLVM. */ |
5 | | |
6 | | /* LLVM-commit: <commit> */ |
7 | | /* LLVM-tag: <tag> */ |
8 | | |
9 | | /* Only small edits allowed. */ |
10 | | /* For multiple similar edits, please create a Patch for the translator. */ |
11 | | |
12 | | /* Capstone's C++ file translator: */ |
13 | | /* https://github.com/capstone-engine/capstone/tree/next/suite/auto-sync */ |
14 | | |
15 | | //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==// |
16 | | // |
17 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
18 | | // See https://llvm.org/LICENSE.txt for license information. |
19 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
20 | | // |
21 | | //===----------------------------------------------------------------------===// |
22 | | // |
23 | | // This class prints an Sparc MCInst to a .s file. |
24 | | // |
25 | | //===----------------------------------------------------------------------===// |
26 | | |
27 | | #include <stdio.h> |
28 | | #include <string.h> |
29 | | #include <stdlib.h> |
30 | | #include <capstone/platform.h> |
31 | | |
32 | | #include "../../MCInstPrinter.h" |
33 | | #include "../../Mapping.h" |
34 | | #include "SparcInstPrinter.h" |
35 | | #include "SparcLinkage.h" |
36 | | #include "SparcMCTargetDesc.h" |
37 | | #include "SparcMapping.h" |
38 | | #include "SparcDisassemblerExtension.h" |
39 | | |
40 | | #define CONCAT(a, b) CONCAT_(a, b) |
41 | | #define CONCAT_(a, b) a##_##b |
42 | | |
43 | | #define DEBUG_TYPE "asm-printer" |
44 | | |
45 | | static void printCustomAliasOperand( |
46 | | MCInst *MI, uint64_t Address, unsigned OpIdx, |
47 | | unsigned PrintMethodIdx, |
48 | | SStream *OS); |
49 | | static void printOperand(MCInst *MI, int opNum, SStream *O); |
50 | | |
51 | | #define GET_INSTRUCTION_NAME |
52 | | #define PRINT_ALIAS_INSTR |
53 | | #include "SparcGenAsmWriter.inc" |
54 | | |
55 | | static void printRegName(SStream *OS, MCRegister Reg) |
56 | 3.58k | { |
57 | 3.58k | SStream_concat1(OS, '%'); |
58 | 3.58k | SStream_concat0(OS, getRegisterName(Reg, Sparc_NoRegAltName)); |
59 | 3.58k | } |
60 | | |
61 | | static void printRegNameAlt(SStream *OS, MCRegister Reg, unsigned AltIdx) |
62 | 22.2k | { |
63 | 22.2k | SStream_concat1(OS, '%'); |
64 | 22.2k | SStream_concat0(OS, getRegisterName(Reg, AltIdx)); |
65 | 22.2k | } |
66 | | |
67 | | static void printInst(MCInst *MI, uint64_t Address, SStream *O) |
68 | 27.3k | { |
69 | 27.3k | bool isAlias = false; |
70 | 27.3k | bool useAliasDetails = map_use_alias_details(MI); |
71 | 27.3k | map_set_fill_detail_ops(MI, useAliasDetails); |
72 | | |
73 | 27.3k | if (!printAliasInstr(MI, Address, O) && |
74 | 27.3k | !printSparcAliasInstr(MI, O)) { |
75 | 22.2k | MCInst_setIsAlias(MI, false); |
76 | 22.2k | } else { |
77 | 5.09k | isAlias = true; |
78 | 5.09k | MCInst_setIsAlias(MI, isAlias); |
79 | 5.09k | if (useAliasDetails) { |
80 | 5.09k | return; |
81 | 5.09k | } |
82 | 5.09k | } |
83 | | |
84 | 22.2k | if (!isAlias || !useAliasDetails) { |
85 | 22.2k | map_set_fill_detail_ops(MI, !(isAlias && useAliasDetails)); |
86 | 22.2k | if (isAlias) |
87 | 0 | SStream_Close(O); |
88 | 22.2k | printInstruction(MI, Address, O); |
89 | 22.2k | if (isAlias) |
90 | 0 | SStream_Open(O); |
91 | 22.2k | } |
92 | 22.2k | } |
93 | | |
94 | | bool printSparcAliasInstr(MCInst *MI, SStream *O) |
95 | 22.3k | { |
96 | 22.3k | switch (MCInst_getOpcode(MI)) { |
97 | 21.8k | default: |
98 | 21.8k | return false; |
99 | 31 | case Sparc_JMPLrr: |
100 | 164 | case Sparc_JMPLri: { |
101 | 164 | if (MCInst_getNumOperands(MI) != 3) |
102 | 0 | return false; |
103 | 164 | if (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) |
104 | 0 | return false; |
105 | 164 | switch (MCOperand_getReg(MCInst_getOperand(MI, (0)))) { |
106 | 39 | default: |
107 | 39 | return false; |
108 | 111 | case Sparc_G0: // jmp $addr | ret | retl |
109 | 111 | if (MCOperand_isImm(MCInst_getOperand(MI, (2))) && |
110 | 111 | MCOperand_getImm(MCInst_getOperand(MI, (2))) == 8) { |
111 | 72 | switch (MCOperand_getReg( |
112 | 72 | MCInst_getOperand(MI, (1)))) { |
113 | 8 | default: |
114 | 8 | break; |
115 | 8 | case Sparc_I7: |
116 | 4 | SStream_concat0(O, "\tret"); |
117 | 4 | return true; |
118 | 60 | case Sparc_O7: |
119 | 60 | SStream_concat0(O, "\tretl"); |
120 | 60 | return true; |
121 | 72 | } |
122 | 72 | } |
123 | 47 | SStream_concat0(O, "\tjmp "); |
124 | 47 | printMemOperand(MI, 1, O); |
125 | 47 | return true; |
126 | 14 | case Sparc_O7: // call $addr |
127 | 14 | SStream_concat0(O, "\tcall "); |
128 | 14 | printMemOperand(MI, 1, O); |
129 | 14 | return true; |
130 | 164 | } |
131 | 164 | } |
132 | 8 | case Sparc_V9FCMPS: |
133 | 34 | case Sparc_V9FCMPD: |
134 | 105 | case Sparc_V9FCMPQ: |
135 | 122 | case Sparc_V9FCMPES: |
136 | 285 | case Sparc_V9FCMPED: |
137 | 319 | case Sparc_V9FCMPEQ: { |
138 | 319 | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) || (MCInst_getNumOperands(MI) != 3) || |
139 | 319 | (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) || |
140 | 319 | (MCOperand_getReg(MCInst_getOperand(MI, (0))) != Sparc_FCC0)) |
141 | 319 | return false; |
142 | | // if V8, skip printing %fcc0. |
143 | 0 | switch (MCInst_getOpcode(MI)) { |
144 | 0 | default: |
145 | 0 | case Sparc_V9FCMPS: |
146 | 0 | SStream_concat0(O, "\tfcmps "); |
147 | 0 | break; |
148 | 0 | case Sparc_V9FCMPD: |
149 | 0 | SStream_concat0(O, "\tfcmpd "); |
150 | 0 | break; |
151 | 0 | case Sparc_V9FCMPQ: |
152 | 0 | SStream_concat0(O, "\tfcmpq "); |
153 | 0 | break; |
154 | 0 | case Sparc_V9FCMPES: |
155 | 0 | SStream_concat0(O, "\tfcmpes "); |
156 | 0 | break; |
157 | 0 | case Sparc_V9FCMPED: |
158 | 0 | SStream_concat0(O, "\tfcmped "); |
159 | 0 | break; |
160 | 0 | case Sparc_V9FCMPEQ: |
161 | 0 | SStream_concat0(O, "\tfcmpeq "); |
162 | 0 | break; |
163 | 0 | } |
164 | 0 | printOperand(MI, 1, O); |
165 | 0 | SStream_concat0(O, ", "); |
166 | 0 | printOperand(MI, 2, O); |
167 | 0 | return true; |
168 | 0 | } |
169 | 22.3k | } |
170 | 22.3k | } |
171 | | |
172 | | static void printOperand(MCInst *MI, int opNum, SStream *O) |
173 | 48.5k | { |
174 | 48.5k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_Operand, opNum); |
175 | 48.5k | MCOperand *MO = MCInst_getOperand(MI, (opNum)); |
176 | | |
177 | 48.5k | if (MCOperand_isReg(MO)) { |
178 | 25.8k | unsigned Reg = MCOperand_getReg(MO); |
179 | 25.8k | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9)) |
180 | 22.2k | printRegNameAlt(O, Reg, Sparc_RegNamesStateReg); |
181 | 3.58k | else |
182 | 3.58k | printRegName(O, Reg); |
183 | 25.8k | return; |
184 | 25.8k | } |
185 | | |
186 | 22.6k | if (MCOperand_isImm(MO)) { |
187 | 22.6k | switch (MCInst_getOpcode(MI)) { |
188 | 22.5k | default: |
189 | 22.5k | printInt32(O, (int)MCOperand_getImm(MO)); |
190 | 22.5k | return; |
191 | | |
192 | 7 | case Sparc_TICCri: // Fall through |
193 | 7 | case Sparc_TICCrr: // Fall through |
194 | 13 | case Sparc_TRAPri: // Fall through |
195 | 13 | case Sparc_TRAPrr: // Fall through |
196 | 130 | case Sparc_TXCCri: // Fall through |
197 | 130 | case Sparc_TXCCrr: // Fall through |
198 | | // Only seven-bit values up to 127. |
199 | 130 | printInt8(O, ((int)MCOperand_getImm(MO) & 0x7f)); |
200 | 130 | return; |
201 | 22.6k | } |
202 | 22.6k | } |
203 | | |
204 | 0 | CS_ASSERT(MCOperand_isExpr(MO) && |
205 | 0 | "Unknown operand kind in printOperand"); |
206 | 0 | } |
207 | | |
208 | | void printMemOperand(MCInst *MI, int opNum, SStream *O) |
209 | 5.84k | { |
210 | 5.84k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MemOperand, opNum); |
211 | 5.84k | MCOperand *Op1 = MCInst_getOperand(MI, (opNum)); |
212 | 5.84k | MCOperand *Op2 = MCInst_getOperand(MI, (opNum + 1)); |
213 | | |
214 | 5.84k | bool PrintedFirstOperand = false; |
215 | 5.84k | if (MCOperand_isReg(Op1) && MCOperand_getReg(Op1) != Sparc_G0) { |
216 | 5.66k | printOperand(MI, opNum, O); |
217 | 5.66k | PrintedFirstOperand = true; |
218 | 5.66k | } |
219 | | |
220 | | // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've |
221 | | // already printed the first one |
222 | 5.84k | const bool SkipSecondOperand = |
223 | 5.84k | PrintedFirstOperand && |
224 | 5.84k | ((MCOperand_isReg(Op2) && MCOperand_getReg(Op2) == Sparc_G0) || |
225 | 5.66k | (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0)); |
226 | | |
227 | 5.84k | if (!SkipSecondOperand) { |
228 | 5.26k | if (PrintedFirstOperand) |
229 | 5.08k | SStream_concat0(O, "+"); |
230 | | |
231 | 5.26k | printOperand(MI, opNum + 1, O); |
232 | 5.26k | } |
233 | 5.84k | } |
234 | | |
235 | | void printCCOperand(MCInst *MI, int opNum, SStream *O) |
236 | 3.20k | { |
237 | 3.20k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_CCOperand, opNum); |
238 | 3.20k | int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
239 | 3.20k | switch (MCInst_getOpcode(MI)) { |
240 | 746 | default: |
241 | 746 | break; |
242 | 746 | case Sparc_FBCOND: |
243 | 740 | case Sparc_FBCONDA: |
244 | 772 | case Sparc_FBCOND_V9: |
245 | 810 | case Sparc_FBCONDA_V9: |
246 | 1.09k | case Sparc_BPFCC: |
247 | 1.35k | case Sparc_BPFCCA: |
248 | 1.35k | case Sparc_BPFCCNT: |
249 | 1.35k | case Sparc_BPFCCANT: |
250 | 1.41k | case Sparc_MOVFCCrr: |
251 | 1.41k | case Sparc_V9MOVFCCrr: |
252 | 1.48k | case Sparc_MOVFCCri: |
253 | 1.48k | case Sparc_V9MOVFCCri: |
254 | 1.48k | case Sparc_FMOVS_FCC: |
255 | 1.48k | case Sparc_V9FMOVS_FCC: |
256 | 1.49k | case Sparc_FMOVD_FCC: |
257 | 1.49k | case Sparc_V9FMOVD_FCC: |
258 | 1.49k | case Sparc_FMOVQ_FCC: |
259 | 1.49k | case Sparc_V9FMOVQ_FCC: |
260 | | // Make sure CC is a fp conditional flag. |
261 | 1.49k | CC = (CC < SPARC_CC_FCC_BEGIN) ? (CC + SPARC_CC_FCC_BEGIN) : CC; |
262 | 1.49k | break; |
263 | 209 | case Sparc_CBCOND: |
264 | 357 | case Sparc_CBCONDA: |
265 | | // Make sure CC is a cp conditional flag. |
266 | 357 | CC = (CC < SPARC_CC_CPCC_BEGIN) ? (CC + SPARC_CC_CPCC_BEGIN) : CC; |
267 | 357 | break; |
268 | 260 | case Sparc_BPR: |
269 | 503 | case Sparc_BPRA: |
270 | 574 | case Sparc_BPRNT: |
271 | 582 | case Sparc_BPRANT: |
272 | 587 | case Sparc_MOVRri: |
273 | 592 | case Sparc_MOVRrr: |
274 | 597 | case Sparc_FMOVRS: |
275 | 602 | case Sparc_FMOVRD: |
276 | 605 | case Sparc_FMOVRQ: |
277 | | // Make sure CC is a register conditional flag. |
278 | 605 | CC = (CC < SPARC_CC_REG_BEGIN) ? (CC + SPARC_CC_REG_BEGIN) : CC; |
279 | 605 | break; |
280 | 3.20k | } |
281 | 3.20k | SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC)); |
282 | 3.20k | } |
283 | | |
284 | | bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O) |
285 | 0 | { |
286 | 0 | printf("FIXME: Implement SparcInstPrinter::printGetPCX."); |
287 | 0 | return true; |
288 | 0 | } |
289 | | |
290 | | void printMembarTag(MCInst *MI, int opNum, SStream *O) |
291 | 10 | { |
292 | 10 | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MembarTag, opNum); |
293 | 10 | static const char *const TagNames[] = { "#LoadLoad", "#StoreLoad", |
294 | 10 | "#LoadStore", "#StoreStore", |
295 | 10 | "#Lookaside", "#MemIssue", |
296 | 10 | "#Sync" }; |
297 | | |
298 | 10 | unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
299 | | |
300 | 10 | if (Imm > 127) { |
301 | 9 | printUInt32(O, Imm); |
302 | 9 | return; |
303 | 9 | } |
304 | | |
305 | 1 | bool First = true; |
306 | 57 | for (unsigned i = 0; i < sizeof(TagNames); i++) { |
307 | 56 | if (Imm & (1ull << i)) { |
308 | 4 | SStream_concat(O, "%s", (First ? "" : " | ")); |
309 | 4 | SStream_concat0(O, TagNames[i]); |
310 | 4 | First = false; |
311 | 4 | } |
312 | 56 | } |
313 | 1 | } |
314 | | |
315 | | #define GET_ASITAG_IMPL |
316 | | #include "SparcGenSystemOperands.inc" |
317 | | |
318 | | void printASITag(MCInst *MI, int opNum, SStream *O) |
319 | 1.40k | { |
320 | 1.40k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_ASITag, opNum); |
321 | 1.40k | unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
322 | 1.40k | const Sparc_ASITag_ASITag *ASITag = Sparc_ASITag_lookupASITagByEncoding(Imm); |
323 | 1.40k | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) && ASITag) { |
324 | 40 | SStream_concat1(O, '#'); |
325 | 40 | SStream_concat0(O, ASITag->Name); |
326 | 40 | } else |
327 | 1.36k | printUInt32(O, Imm); |
328 | 1.40k | } |
329 | | |
330 | | |
331 | | void Sparc_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot, |
332 | | SStream *O) |
333 | 27.3k | { |
334 | 27.3k | printInst(MI, Address, O); |
335 | 27.3k | } |
336 | | |
337 | | const char *Sparc_LLVM_getRegisterName(unsigned RegNo, unsigned AltIdx) |
338 | 14.0k | { |
339 | 14.0k | return getRegisterName(RegNo, AltIdx); |
340 | 14.0k | } |