1 //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax --------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class prints an Sparc MCInst to a .s file.
11 //
12 //===----------------------------------------------------------------------===//
13
14 /* Capstone Disassembly Engine */
15 /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
16
17 #ifdef CAPSTONE_HAS_SPARC
18
19 #ifdef _MSC_VER
20 #define _CRT_SECURE_NO_WARNINGS
21 #endif
22
23 #if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)
24 #pragma warning(disable:28719) // disable MSVC's warning on strncpy()
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include "SparcInstPrinter.h"
32 #include "../../MCInst.h"
33 #include "../../utils.h"
34 #include "../../SStream.h"
35 #include "../../MCRegisterInfo.h"
36 #include "../../MathExtras.h"
37 #include "SparcMapping.h"
38
39 #include "Sparc.h"
40
41 static char *getRegisterName(unsigned RegNo);
42 static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
43 static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier);
44 static void printOperand(MCInst *MI, int opNum, SStream *O);
45
Sparc_add_hint(MCInst * MI,unsigned int hint)46 static void Sparc_add_hint(MCInst *MI, unsigned int hint)
47 {
48 if (MI->csh->detail) {
49 MI->flat_insn->detail->sparc.hint = hint;
50 }
51 }
52
Sparc_add_reg(MCInst * MI,unsigned int reg)53 static void Sparc_add_reg(MCInst *MI, unsigned int reg)
54 {
55 if (MI->csh->detail) {
56 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
57 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
58 MI->flat_insn->detail->sparc.op_count++;
59 }
60 }
61
set_mem_access(MCInst * MI,bool status)62 static void set_mem_access(MCInst *MI, bool status)
63 {
64 if (MI->csh->detail != CS_OPT_ON)
65 return;
66
67 MI->csh->doing_mem = status;
68
69 if (status) {
70 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
71 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
72 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
73 } else {
74 // done, create the next operand slot
75 MI->flat_insn->detail->sparc.op_count++;
76 }
77 }
78
Sparc_post_printer(csh ud,cs_insn * insn,char * insn_asm,MCInst * mci)79 void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
80 {
81 if (((cs_struct *)ud)->detail != CS_OPT_ON)
82 return;
83
84 // fix up some instructions
85 if (insn->id == SPARC_INS_CASX) {
86 // first op is actually a memop, not regop
87 insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
88 insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
89 insn->detail->sparc.operands[0].mem.disp = 0;
90 }
91 }
92
printRegName(SStream * OS,unsigned RegNo)93 static void printRegName(SStream *OS, unsigned RegNo)
94 {
95 SStream_concat0(OS, "%");
96 SStream_concat0(OS, getRegisterName(RegNo));
97 }
98
99 #define GET_INSTRINFO_ENUM
100 #include "SparcGenInstrInfo.inc"
101
102 #define GET_REGINFO_ENUM
103 #include "SparcGenRegisterInfo.inc"
104
printSparcAliasInstr(MCInst * MI,SStream * O)105 static bool printSparcAliasInstr(MCInst *MI, SStream *O)
106 {
107 switch (MCInst_getOpcode(MI)) {
108 default: return false;
109 case SP_JMPLrr:
110 case SP_JMPLri:
111 if (MCInst_getNumOperands(MI) != 3)
112 return false;
113 if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
114 return false;
115
116 switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
117 default: return false;
118 case SP_G0: // jmp $addr | ret | retl
119 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
120 MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
121 switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
122 default: break;
123 case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true;
124 case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true;
125 }
126 }
127
128 SStream_concat0(O, "jmp\t");
129 MCInst_setOpcodePub(MI, SPARC_INS_JMP);
130 printMemOperand(MI, 1, O, NULL);
131 return true;
132 case SP_O7: // call $addr
133 SStream_concat0(O, "call ");
134 MCInst_setOpcodePub(MI, SPARC_INS_CALL);
135 printMemOperand(MI, 1, O, NULL);
136 return true;
137 }
138 case SP_V9FCMPS:
139 case SP_V9FCMPD:
140 case SP_V9FCMPQ:
141 case SP_V9FCMPES:
142 case SP_V9FCMPED:
143 case SP_V9FCMPEQ:
144 if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
145 (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
146 (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
147 return false;
148 // if V8, skip printing %fcc0.
149 switch(MCInst_getOpcode(MI)) {
150 default:
151 case SP_V9FCMPS: SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break;
152 case SP_V9FCMPD: SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break;
153 case SP_V9FCMPQ: SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break;
154 case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break;
155 case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break;
156 case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break;
157 }
158 printOperand(MI, 1, O);
159 SStream_concat0(O, ", ");
160 printOperand(MI, 2, O);
161 return true;
162 }
163 }
164
printOperand(MCInst * MI,int opNum,SStream * O)165 static void printOperand(MCInst *MI, int opNum, SStream *O)
166 {
167 int Imm;
168 unsigned reg;
169 MCOperand *MO = MCInst_getOperand(MI, opNum);
170
171 if (MCOperand_isReg(MO)) {
172 reg = MCOperand_getReg(MO);
173 printRegName(O, reg);
174 reg = Sparc_map_register(reg);
175
176 if (MI->csh->detail) {
177 if (MI->csh->doing_mem) {
178 if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
179 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg;
180 else
181 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg;
182 } else {
183 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
184 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
185 MI->flat_insn->detail->sparc.op_count++;
186 }
187 }
188
189 return;
190 }
191
192 if (MCOperand_isImm(MO)) {
193 Imm = (int)MCOperand_getImm(MO);
194
195 // Conditional branches displacements needs to be signextended to be
196 // able to jump backwards.
197 //
198 // Displacements are measured as the number of instructions forward or
199 // backward, so they need to be multiplied by 4
200 switch (MI->Opcode) {
201 case SP_CALL:
202 Imm = SignExtend32(Imm, 30);
203 Imm += (uint32_t)MI->address;
204 break;
205
206 // Branch on integer condition with prediction (BPcc)
207 // Branch on floating point condition with prediction (FBPfcc)
208 case SP_BPICC:
209 case SP_BPICCA:
210 case SP_BPICCANT:
211 case SP_BPICCNT:
212 case SP_BPXCC:
213 case SP_BPXCCA:
214 case SP_BPXCCANT:
215 case SP_BPXCCNT:
216 case SP_BPFCC:
217 case SP_BPFCCA:
218 case SP_BPFCCANT:
219 case SP_BPFCCNT:
220 Imm = SignExtend32(Imm, 19);
221 Imm = (uint32_t)MI->address + Imm * 4;
222 break;
223
224 // Branch on integer condition (Bicc)
225 // Branch on floating point condition (FBfcc)
226 case SP_BA:
227 case SP_BCOND:
228 case SP_BCONDA:
229 case SP_FBCOND:
230 case SP_FBCONDA:
231 Imm = SignExtend32(Imm, 22);
232 Imm = (uint32_t)MI->address + Imm * 4;
233 break;
234
235 // Branch on integer register with prediction (BPr)
236 case SP_BPGEZapn:
237 case SP_BPGEZapt:
238 case SP_BPGEZnapn:
239 case SP_BPGEZnapt:
240 case SP_BPGZapn:
241 case SP_BPGZapt:
242 case SP_BPGZnapn:
243 case SP_BPGZnapt:
244 case SP_BPLEZapn:
245 case SP_BPLEZapt:
246 case SP_BPLEZnapn:
247 case SP_BPLEZnapt:
248 case SP_BPLZapn:
249 case SP_BPLZapt:
250 case SP_BPLZnapn:
251 case SP_BPLZnapt:
252 case SP_BPNZapn:
253 case SP_BPNZapt:
254 case SP_BPNZnapn:
255 case SP_BPNZnapt:
256 case SP_BPZapn:
257 case SP_BPZapt:
258 case SP_BPZnapn:
259 case SP_BPZnapt:
260 Imm = SignExtend32(Imm, 16);
261 Imm = (uint32_t)MI->address + Imm * 4;
262 break;
263 }
264
265 if (Imm >= 0) {
266 if (Imm > HEX_THRESHOLD)
267 SStream_concat(O, "0x%x", Imm);
268 else
269 SStream_concat(O, "%u", Imm);
270 } else {
271 if (Imm < -HEX_THRESHOLD)
272 SStream_concat(O, "-0x%x", -Imm);
273 else
274 SStream_concat(O, "-%u", -Imm);
275 }
276
277 if (MI->csh->detail) {
278 if (MI->csh->doing_mem) {
279 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
280 } else {
281 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
282 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
283 MI->flat_insn->detail->sparc.op_count++;
284 }
285 }
286 }
287
288 return;
289 }
290
printMemOperand(MCInst * MI,int opNum,SStream * O,const char * Modifier)291 static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
292 {
293 MCOperand *MO;
294
295 set_mem_access(MI, true);
296 printOperand(MI, opNum, O);
297
298 // If this is an ADD operand, emit it like normal operands.
299 if (Modifier && !strcmp(Modifier, "arith")) {
300 SStream_concat0(O, ", ");
301 printOperand(MI, opNum + 1, O);
302 set_mem_access(MI, false);
303 return;
304 }
305
306 MO = MCInst_getOperand(MI, opNum + 1);
307
308 if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
309 set_mem_access(MI, false);
310 return; // don't print "+%g0"
311 }
312
313 if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
314 set_mem_access(MI, false);
315 return; // don't print "+0"
316 }
317
318 SStream_concat0(O, "+"); // qq
319
320 printOperand(MI, opNum + 1, O);
321 set_mem_access(MI, false);
322 }
323
printCCOperand(MCInst * MI,int opNum,SStream * O)324 static void printCCOperand(MCInst *MI, int opNum, SStream *O)
325 {
326 int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
327
328 switch (MCInst_getOpcode(MI)) {
329 default: break;
330 case SP_FBCOND:
331 case SP_FBCONDA:
332 case SP_BPFCC:
333 case SP_BPFCCA:
334 case SP_BPFCCNT:
335 case SP_BPFCCANT:
336 case SP_MOVFCCrr: case SP_V9MOVFCCrr:
337 case SP_MOVFCCri: case SP_V9MOVFCCri:
338 case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
339 case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
340 case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
341 // Make sure CC is a fp conditional flag.
342 CC = (CC < 16+256) ? (CC + 16) : CC;
343 break;
344 }
345
346 SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
347
348 if (MI->csh->detail)
349 MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
350 }
351
352
printGetPCX(MCInst * MI,unsigned opNum,SStream * O)353 static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
354 {
355 return true;
356 }
357
358
359 #define PRINT_ALIAS_INSTR
360 #include "SparcGenAsmWriter.inc"
361
Sparc_printInst(MCInst * MI,SStream * O,void * Info)362 void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
363 {
364 char *mnem, *p;
365 char instr[64]; // Sparc has no instruction this long
366
367 mnem = printAliasInstr(MI, O, Info);
368 if (mnem) {
369 // fixup instruction id due to the change in alias instruction
370 strncpy(instr, mnem, strlen(mnem));
371 instr[strlen(mnem)] = '\0';
372 // does this contains hint with a coma?
373 p = strchr(instr, ',');
374 if (p)
375 *p = '\0'; // now instr only has instruction mnemonic
376 MCInst_setOpcodePub(MI, Sparc_map_insn(instr));
377 switch(MCInst_getOpcode(MI)) {
378 case SP_BCOND:
379 case SP_BCONDA:
380 case SP_BPICCANT:
381 case SP_BPICCNT:
382 case SP_BPXCCANT:
383 case SP_BPXCCNT:
384 case SP_TXCCri:
385 case SP_TXCCrr:
386 if (MI->csh->detail) {
387 // skip 'b', 't'
388 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1);
389 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
390 }
391 break;
392 case SP_BPFCCANT:
393 case SP_BPFCCNT:
394 if (MI->csh->detail) {
395 // skip 'fb'
396 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2);
397 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
398 }
399 break;
400 case SP_FMOVD_ICC:
401 case SP_FMOVD_XCC:
402 case SP_FMOVQ_ICC:
403 case SP_FMOVQ_XCC:
404 case SP_FMOVS_ICC:
405 case SP_FMOVS_XCC:
406 if (MI->csh->detail) {
407 // skip 'fmovd', 'fmovq', 'fmovs'
408 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5);
409 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
410 }
411 break;
412 case SP_MOVICCri:
413 case SP_MOVICCrr:
414 case SP_MOVXCCri:
415 case SP_MOVXCCrr:
416 if (MI->csh->detail) {
417 // skip 'mov'
418 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3);
419 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
420 }
421 break;
422 case SP_V9FMOVD_FCC:
423 case SP_V9FMOVQ_FCC:
424 case SP_V9FMOVS_FCC:
425 if (MI->csh->detail) {
426 // skip 'fmovd', 'fmovq', 'fmovs'
427 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5);
428 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
429 }
430 break;
431 case SP_V9MOVFCCri:
432 case SP_V9MOVFCCrr:
433 if (MI->csh->detail) {
434 // skip 'mov'
435 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3);
436 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
437 }
438 break;
439 default:
440 break;
441 }
442 cs_mem_free(mnem);
443 } else {
444 if (!printSparcAliasInstr(MI, O))
445 printInstruction(MI, O, NULL);
446 }
447 }
448
Sparc_addReg(MCInst * MI,int reg)449 void Sparc_addReg(MCInst *MI, int reg)
450 {
451 if (MI->csh->detail) {
452 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
453 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
454 MI->flat_insn->detail->sparc.op_count++;
455 }
456 }
457
458 #endif
459