/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 | 63.2k | { |
57 | 63.2k | SStream_concat1(OS, '%'); |
58 | 63.2k | SStream_concat0(OS, getRegisterName(Reg, Sparc_NoRegAltName)); |
59 | 63.2k | } |
60 | | |
61 | | static void printRegNameAlt(SStream *OS, MCRegister Reg, unsigned AltIdx) |
62 | 27.7k | { |
63 | 27.7k | SStream_concat1(OS, '%'); |
64 | 27.7k | SStream_concat0(OS, getRegisterName(Reg, AltIdx)); |
65 | 27.7k | } |
66 | | |
67 | | static void printInst(MCInst *MI, uint64_t Address, SStream *O) |
68 | 31.8k | { |
69 | 31.8k | bool isAlias = false; |
70 | 31.8k | bool useAliasDetails = map_use_alias_details(MI); |
71 | 31.8k | map_set_fill_detail_ops(MI, useAliasDetails); |
72 | | |
73 | 31.8k | if (!printAliasInstr(MI, Address, O) && |
74 | 31.8k | !printSparcAliasInstr(MI, O)) { |
75 | 26.4k | MCInst_setIsAlias(MI, false); |
76 | 26.4k | } else { |
77 | 5.43k | isAlias = true; |
78 | 5.43k | MCInst_setIsAlias(MI, isAlias); |
79 | 5.43k | if (useAliasDetails) { |
80 | 5.43k | return; |
81 | 5.43k | } |
82 | 5.43k | } |
83 | | |
84 | 26.4k | if (!isAlias || !useAliasDetails) { |
85 | 26.4k | map_set_fill_detail_ops(MI, !(isAlias && useAliasDetails)); |
86 | 26.4k | if (isAlias) |
87 | 0 | SStream_Close(O); |
88 | 26.4k | printInstruction(MI, Address, O); |
89 | 26.4k | if (isAlias) |
90 | 0 | SStream_Open(O); |
91 | 26.4k | } |
92 | 26.4k | } |
93 | | |
94 | | bool printSparcAliasInstr(MCInst *MI, SStream *O) |
95 | 26.6k | { |
96 | 26.6k | switch (MCInst_getOpcode(MI)) { |
97 | 25.8k | default: |
98 | 25.8k | return false; |
99 | 48 | case Sparc_JMPLrr: |
100 | 262 | case Sparc_JMPLri: { |
101 | 262 | if (MCInst_getNumOperands(MI) != 3) |
102 | 0 | return false; |
103 | 262 | if (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) |
104 | 0 | return false; |
105 | 262 | switch (MCOperand_getReg(MCInst_getOperand(MI, (0)))) { |
106 | 43 | default: |
107 | 43 | return false; |
108 | 199 | case Sparc_G0: // jmp $addr | ret | retl |
109 | 199 | if (MCOperand_isImm(MCInst_getOperand(MI, (2))) && |
110 | 199 | MCOperand_getImm(MCInst_getOperand(MI, (2))) == 8) { |
111 | 101 | switch (MCOperand_getReg( |
112 | 101 | MCInst_getOperand(MI, (1)))) { |
113 | 13 | default: |
114 | 13 | break; |
115 | 13 | case Sparc_I7: |
116 | 10 | SStream_concat0(O, "\tret"); |
117 | 10 | return true; |
118 | 78 | case Sparc_O7: |
119 | 78 | SStream_concat0(O, "\tretl"); |
120 | 78 | return true; |
121 | 101 | } |
122 | 101 | } |
123 | 111 | SStream_concat0(O, "\tjmp "); |
124 | 111 | printMemOperand(MI, 1, O); |
125 | 111 | return true; |
126 | 20 | case Sparc_O7: // call $addr |
127 | 20 | SStream_concat0(O, "\tcall "); |
128 | 20 | printMemOperand(MI, 1, O); |
129 | 20 | return true; |
130 | 262 | } |
131 | 262 | } |
132 | 10 | case Sparc_V9FCMPS: |
133 | 181 | case Sparc_V9FCMPD: |
134 | 282 | case Sparc_V9FCMPQ: |
135 | 301 | case Sparc_V9FCMPES: |
136 | 504 | case Sparc_V9FCMPED: |
137 | 539 | case Sparc_V9FCMPEQ: { |
138 | 539 | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) || (MCInst_getNumOperands(MI) != 3) || |
139 | 539 | (!MCOperand_isReg(MCInst_getOperand(MI, (0)))) || |
140 | 539 | (MCOperand_getReg(MCInst_getOperand(MI, (0))) != Sparc_FCC0)) |
141 | 539 | 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 | 26.6k | } |
170 | 26.6k | } |
171 | | |
172 | | static void printOperand(MCInst *MI, int opNum, SStream *O) |
173 | 57.7k | { |
174 | 57.7k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_Operand, opNum); |
175 | 57.7k | MCOperand *MO = MCInst_getOperand(MI, (opNum)); |
176 | | |
177 | 57.7k | if (MCOperand_isReg(MO)) { |
178 | 32.8k | unsigned Reg = MCOperand_getReg(MO); |
179 | 32.8k | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9)) |
180 | 27.7k | printRegNameAlt(O, Reg, Sparc_RegNamesStateReg); |
181 | 5.13k | else |
182 | 5.13k | printRegName(O, Reg); |
183 | 32.8k | return; |
184 | 32.8k | } |
185 | | |
186 | 24.8k | if (MCOperand_isImm(MO)) { |
187 | 24.8k | switch (MCInst_getOpcode(MI)) { |
188 | 24.7k | default: |
189 | 24.7k | printInt32(O, (int)MCOperand_getImm(MO)); |
190 | 24.7k | return; |
191 | | |
192 | 15 | case Sparc_TICCri: // Fall through |
193 | 15 | case Sparc_TICCrr: // Fall through |
194 | 25 | case Sparc_TRAPri: // Fall through |
195 | 25 | case Sparc_TRAPrr: // Fall through |
196 | 145 | case Sparc_TXCCri: // Fall through |
197 | 145 | case Sparc_TXCCrr: // Fall through |
198 | | // Only seven-bit values up to 127. |
199 | 145 | printInt8(O, ((int)MCOperand_getImm(MO) & 0x7f)); |
200 | 145 | return; |
201 | 24.8k | } |
202 | 24.8k | } |
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 | 6.68k | { |
210 | 6.68k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MemOperand, opNum); |
211 | 6.68k | MCOperand *Op1 = MCInst_getOperand(MI, (opNum)); |
212 | 6.68k | MCOperand *Op2 = MCInst_getOperand(MI, (opNum + 1)); |
213 | | |
214 | 6.68k | bool PrintedFirstOperand = false; |
215 | 6.68k | if (MCOperand_isReg(Op1) && MCOperand_getReg(Op1) != Sparc_G0) { |
216 | 6.29k | printOperand(MI, opNum, O); |
217 | 6.29k | PrintedFirstOperand = true; |
218 | 6.29k | } |
219 | | |
220 | | // Skip the second operand iff it adds nothing (literal 0 or %g0) and we've |
221 | | // already printed the first one |
222 | 6.68k | const bool SkipSecondOperand = |
223 | 6.68k | PrintedFirstOperand && |
224 | 6.68k | ((MCOperand_isReg(Op2) && MCOperand_getReg(Op2) == Sparc_G0) || |
225 | 6.29k | (MCOperand_isImm(Op2) && MCOperand_getImm(Op2) == 0)); |
226 | | |
227 | 6.68k | if (!SkipSecondOperand) { |
228 | 6.01k | if (PrintedFirstOperand) |
229 | 5.62k | SStream_concat0(O, "+"); |
230 | | |
231 | 6.01k | printOperand(MI, opNum + 1, O); |
232 | 6.01k | } |
233 | 6.68k | } |
234 | | |
235 | | void printCCOperand(MCInst *MI, int opNum, SStream *O) |
236 | 5.47k | { |
237 | 5.47k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_CCOperand, opNum); |
238 | 5.47k | int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
239 | 5.47k | switch (MCInst_getOpcode(MI)) { |
240 | 1.27k | default: |
241 | 1.27k | break; |
242 | 1.27k | case Sparc_FBCOND: |
243 | 923 | case Sparc_FBCONDA: |
244 | 1.02k | case Sparc_FBCOND_V9: |
245 | 1.10k | case Sparc_FBCONDA_V9: |
246 | 1.48k | case Sparc_BPFCC: |
247 | 1.80k | case Sparc_BPFCCA: |
248 | 1.80k | case Sparc_BPFCCNT: |
249 | 1.80k | case Sparc_BPFCCANT: |
250 | 1.89k | case Sparc_MOVFCCrr: |
251 | 1.89k | case Sparc_V9MOVFCCrr: |
252 | 1.97k | case Sparc_MOVFCCri: |
253 | 1.97k | case Sparc_V9MOVFCCri: |
254 | 1.98k | case Sparc_FMOVS_FCC: |
255 | 1.98k | case Sparc_V9FMOVS_FCC: |
256 | 1.99k | case Sparc_FMOVD_FCC: |
257 | 1.99k | case Sparc_V9FMOVD_FCC: |
258 | 1.99k | case Sparc_FMOVQ_FCC: |
259 | 1.99k | case Sparc_V9FMOVQ_FCC: |
260 | | // Make sure CC is a fp conditional flag. |
261 | 1.99k | CC = (CC < SPARC_CC_FCC_BEGIN) ? (CC + SPARC_CC_FCC_BEGIN) : CC; |
262 | 1.99k | break; |
263 | 635 | case Sparc_CBCOND: |
264 | 1.16k | case Sparc_CBCONDA: |
265 | | // Make sure CC is a cp conditional flag. |
266 | 1.16k | CC = (CC < SPARC_CC_CPCC_BEGIN) ? (CC + SPARC_CC_CPCC_BEGIN) : CC; |
267 | 1.16k | break; |
268 | 357 | case Sparc_BPR: |
269 | 784 | case Sparc_BPRA: |
270 | 915 | case Sparc_BPRNT: |
271 | 970 | case Sparc_BPRANT: |
272 | 990 | case Sparc_MOVRri: |
273 | 1.00k | case Sparc_MOVRrr: |
274 | 1.01k | case Sparc_FMOVRS: |
275 | 1.02k | case Sparc_FMOVRD: |
276 | 1.04k | case Sparc_FMOVRQ: |
277 | | // Make sure CC is a register conditional flag. |
278 | 1.04k | CC = (CC < SPARC_CC_REG_BEGIN) ? (CC + SPARC_CC_REG_BEGIN) : CC; |
279 | 1.04k | break; |
280 | 5.47k | } |
281 | 5.47k | SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC)); |
282 | 5.47k | } |
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 | 43 | { |
292 | 43 | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_MembarTag, opNum); |
293 | 43 | static const char *const TagNames[] = { "#LoadLoad", "#StoreLoad", |
294 | 43 | "#LoadStore", "#StoreStore", |
295 | 43 | "#Lookaside", "#MemIssue", |
296 | 43 | "#Sync" }; |
297 | | |
298 | 43 | unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
299 | | |
300 | 43 | if (Imm > 127) { |
301 | 12 | printUInt32(O, Imm); |
302 | 12 | return; |
303 | 12 | } |
304 | | |
305 | 31 | bool First = true; |
306 | 1.76k | for (unsigned i = 0; i < sizeof(TagNames); i++) { |
307 | 1.73k | if (Imm & (1ull << i)) { |
308 | 80 | SStream_concat(O, "%s", (First ? "" : " | ")); |
309 | 80 | SStream_concat0(O, TagNames[i]); |
310 | 80 | First = false; |
311 | 80 | } |
312 | 1.73k | } |
313 | 31 | } |
314 | | |
315 | | #define GET_ASITAG_IMPL |
316 | | #include "SparcGenSystemOperands.inc" |
317 | | |
318 | | void printASITag(MCInst *MI, int opNum, SStream *O) |
319 | 2.54k | { |
320 | 2.54k | Sparc_add_cs_detail_0(MI, Sparc_OP_GROUP_ASITag, opNum); |
321 | 2.54k | unsigned Imm = MCOperand_getImm(MCInst_getOperand(MI, (opNum))); |
322 | 2.54k | const Sparc_ASITag_ASITag *ASITag = Sparc_ASITag_lookupASITagByEncoding(Imm); |
323 | 2.54k | if (Sparc_getFeatureBits(MI->csh->mode, Sparc_FeatureV9) && ASITag) { |
324 | 142 | SStream_concat1(O, '#'); |
325 | 142 | SStream_concat0(O, ASITag->Name); |
326 | 142 | } else |
327 | 2.40k | printUInt32(O, Imm); |
328 | 2.54k | } |
329 | | |
330 | | |
331 | | void Sparc_LLVM_printInst(MCInst *MI, uint64_t Address, const char *Annot, |
332 | | SStream *O) |
333 | 31.8k | { |
334 | 31.8k | printInst(MI, Address, O); |
335 | 31.8k | } |
336 | | |
337 | | const char *Sparc_LLVM_getRegisterName(unsigned RegNo, unsigned AltIdx) |
338 | 13.8k | { |
339 | 13.8k | return getRegisterName(RegNo, AltIdx); |
340 | 13.8k | } |