blob: ba2a315582605d1fedbcae86c66e79b91b26d75f [file] [log] [blame]
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +08001//===-- 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 */
Nguyen Anh Quynhbfcaba52015-03-04 17:45:23 +080015/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080016
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +080017#ifdef CAPSTONE_HAS_SPARC
18
Nguyen Anh Quynh4b6b15f2014-08-26 15:57:04 +080019#ifdef _MSC_VER
20#define _CRT_SECURE_NO_WARNINGS
21#endif
22
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080023#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include "SparcInstPrinter.h"
28#include "../../MCInst.h"
29#include "../../utils.h"
30#include "../../SStream.h"
31#include "../../MCRegisterInfo.h"
32#include "../../MathExtras.h"
33#include "SparcMapping.h"
34
35#include "Sparc.h"
36
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +080037static char *getRegisterName(unsigned RegNo);
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080038static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
39static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier);
40static void printOperand(MCInst *MI, int opNum, SStream *O);
41
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +080042static void Sparc_add_hint(MCInst *MI, unsigned int hint)
43{
44 if (MI->csh->detail) {
45 MI->flat_insn->detail->sparc.hint = hint;
46 }
47}
48
49static void Sparc_add_reg(MCInst *MI, unsigned int reg)
50{
51 if (MI->csh->detail) {
52 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
53 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
54 MI->flat_insn->detail->sparc.op_count++;
55 }
56}
57
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080058static void set_mem_access(MCInst *MI, bool status)
59{
60 if (MI->csh->detail != CS_OPT_ON)
61 return;
62
63 MI->csh->doing_mem = status;
64
65 if (status) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070066 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
67 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
68 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080069 } else {
70 // done, create the next operand slot
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070071 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080072 }
73}
74
Nguyen Anh Quynh64564812014-05-19 16:46:31 +080075void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080076{
77 if (((cs_struct *)ud)->detail != CS_OPT_ON)
78 return;
79
80 // fix up some instructions
81 if (insn->id == SPARC_INS_CASX) {
82 // first op is actually a memop, not regop
83 insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
tandasat45e5eab2016-05-11 21:48:32 -070084 insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080085 insn->detail->sparc.operands[0].mem.disp = 0;
86 }
87}
88
89static void printRegName(SStream *OS, unsigned RegNo)
90{
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +080091 SStream_concat0(OS, "%");
92 SStream_concat0(OS, getRegisterName(RegNo));
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080093}
94
95#define GET_INSTRINFO_ENUM
96#include "SparcGenInstrInfo.inc"
97
98#define GET_REGINFO_ENUM
99#include "SparcGenRegisterInfo.inc"
100
101static bool printSparcAliasInstr(MCInst *MI, SStream *O)
102{
103 switch (MCInst_getOpcode(MI)) {
104 default: return false;
105 case SP_JMPLrr:
106 case SP_JMPLri:
107 if (MCInst_getNumOperands(MI) != 3)
108 return false;
109 if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
110 return false;
111
112 switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
113 default: return false;
114 case SP_G0: // jmp $addr | ret | retl
115 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
116 MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
117 switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
118 default: break;
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +0800119 case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true;
120 case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800121 }
122 }
123
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +0800124 SStream_concat0(O, "jmp\t");
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +0800125 MCInst_setOpcodePub(MI, SPARC_INS_JMP);
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800126 printMemOperand(MI, 1, O, NULL);
127 return true;
128 case SP_O7: // call $addr
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +0800129 SStream_concat0(O, "call ");
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +0800130 MCInst_setOpcodePub(MI, SPARC_INS_CALL);
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800131 printMemOperand(MI, 1, O, NULL);
132 return true;
133 }
134 case SP_V9FCMPS:
135 case SP_V9FCMPD:
136 case SP_V9FCMPQ:
137 case SP_V9FCMPES:
138 case SP_V9FCMPED:
139 case SP_V9FCMPEQ:
140 if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
141 (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
142 (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
143 return false;
144 // if V8, skip printing %fcc0.
145 switch(MCInst_getOpcode(MI)) {
146 default:
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +0800147 case SP_V9FCMPS: SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break;
148 case SP_V9FCMPD: SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break;
149 case SP_V9FCMPQ: SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break;
150 case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break;
151 case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break;
152 case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800153 }
154 printOperand(MI, 1, O);
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +0800155 SStream_concat0(O, ", ");
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800156 printOperand(MI, 2, O);
157 return true;
158 }
159}
160
161static void printOperand(MCInst *MI, int opNum, SStream *O)
162{
163 int Imm;
164 unsigned reg;
165 MCOperand *MO = MCInst_getOperand(MI, opNum);
166
167 if (MCOperand_isReg(MO)) {
168 reg = MCOperand_getReg(MO);
169 printRegName(O, reg);
170 reg = Sparc_map_register(reg);
171
172 if (MI->csh->detail) {
173 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700174 if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
tandasat45e5eab2016-05-11 21:48:32 -0700175 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800176 else
tandasat45e5eab2016-05-11 21:48:32 -0700177 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800178 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700179 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
180 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
181 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800182 }
183 }
184
185 return;
186 }
187
188 if (MCOperand_isImm(MO)) {
189 Imm = (int)MCOperand_getImm(MO);
Nguyen Anh Quynhe16813d2014-11-10 22:20:00 +0800190
NighterMan72ee3c92015-04-11 04:55:16 +0200191 // Conditional branches displacements needs to be signextended to be
192 // able to jump backwards.
193 //
194 // Displacements are measured as the number of instructions forward or
195 // backward, so they need to be multiplied by 4
196 switch (MI->Opcode) {
197 case SP_CALL:
198 Imm = SignExtend32(Imm, 30);
199 Imm += (uint32_t)MI->address;
200 break;
201
202 // Branch on integer condition with prediction (BPcc)
203 // Branch on floating point condition with prediction (FBPfcc)
204 case SP_BPICC:
205 case SP_BPICCA:
206 case SP_BPICCANT:
207 case SP_BPICCNT:
208 case SP_BPXCC:
209 case SP_BPXCCA:
210 case SP_BPXCCANT:
211 case SP_BPXCCNT:
212 case SP_BPFCC:
213 case SP_BPFCCA:
214 case SP_BPFCCANT:
215 case SP_BPFCCNT:
216 Imm = SignExtend32(Imm, 19);
217 Imm = (uint32_t)MI->address + Imm * 4;
218 break;
219
220 // Branch on integer condition (Bicc)
221 // Branch on floating point condition (FBfcc)
222 case SP_BA:
223 case SP_BCOND:
224 case SP_BCONDA:
225 case SP_FBCOND:
226 case SP_FBCONDA:
227 Imm = SignExtend32(Imm, 22);
228 Imm = (uint32_t)MI->address + Imm * 4;
229 break;
230
231 // Branch on integer register with prediction (BPr)
232 case SP_BPGEZapn:
233 case SP_BPGEZapt:
234 case SP_BPGEZnapn:
235 case SP_BPGEZnapt:
236 case SP_BPGZapn:
237 case SP_BPGZapt:
238 case SP_BPGZnapn:
239 case SP_BPGZnapt:
240 case SP_BPLEZapn:
241 case SP_BPLEZapt:
242 case SP_BPLEZnapn:
243 case SP_BPLEZnapt:
244 case SP_BPLZapn:
245 case SP_BPLZapt:
246 case SP_BPLZnapn:
247 case SP_BPLZnapt:
248 case SP_BPNZapn:
249 case SP_BPNZapt:
250 case SP_BPNZnapn:
251 case SP_BPNZnapt:
252 case SP_BPZapn:
253 case SP_BPZapt:
254 case SP_BPZnapn:
255 case SP_BPZnapt:
256 Imm = SignExtend32(Imm, 16);
257 Imm = (uint32_t)MI->address + Imm * 4;
258 break;
259 }
Nguyen Anh Quynhe16813d2014-11-10 22:20:00 +0800260
Nguyen Anh Quynha3c9bd62014-03-26 16:22:16 +0800261 if (Imm >= 0) {
262 if (Imm > HEX_THRESHOLD)
263 SStream_concat(O, "0x%x", Imm);
264 else
265 SStream_concat(O, "%u", Imm);
266 } else {
267 if (Imm < -HEX_THRESHOLD)
268 SStream_concat(O, "-0x%x", -Imm);
269 else
270 SStream_concat(O, "-%u", -Imm);
271 }
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800272
273 if (MI->csh->detail) {
274 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700275 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800276 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700277 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
278 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
279 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800280 }
281 }
282 }
283
284 return;
285}
286
287static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
288{
289 MCOperand *MO;
290
291 set_mem_access(MI, true);
292 printOperand(MI, opNum, O);
293
294 // If this is an ADD operand, emit it like normal operands.
295 if (Modifier && !strcmp(Modifier, "arith")) {
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +0800296 SStream_concat0(O, ", ");
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800297 printOperand(MI, opNum + 1, O);
298 set_mem_access(MI, false);
299 return;
300 }
301
302 MO = MCInst_getOperand(MI, opNum + 1);
303
304 if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
305 set_mem_access(MI, false);
306 return; // don't print "+%g0"
307 }
308
309 if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
310 set_mem_access(MI, false);
311 return; // don't print "+0"
312 }
313
Nguyen Anh Quynh1738a3e2014-09-17 00:01:04 +0800314 SStream_concat0(O, "+"); // qq
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800315
316 printOperand(MI, opNum + 1, O);
317 set_mem_access(MI, false);
318}
319
320static void printCCOperand(MCInst *MI, int opNum, SStream *O)
321{
Nguyen Anh Quynh5d6383e2014-05-25 13:48:06 +0800322 int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800323
324 switch (MCInst_getOpcode(MI)) {
325 default: break;
326 case SP_FBCOND:
327 case SP_FBCONDA:
328 case SP_BPFCC:
329 case SP_BPFCCA:
330 case SP_BPFCCNT:
331 case SP_BPFCCANT:
332 case SP_MOVFCCrr: case SP_V9MOVFCCrr:
333 case SP_MOVFCCri: case SP_V9MOVFCCri:
334 case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
335 case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
336 case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
337 // Make sure CC is a fp conditional flag.
Nguyen Anh Quynh5d6383e2014-05-25 13:48:06 +0800338 CC = (CC < 16+256) ? (CC + 16) : CC;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800339 break;
340 }
341
Nguyen Anh Quynh9b91de02014-06-16 12:51:07 +0800342 SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC));
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800343
344 if (MI->csh->detail)
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700345 MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800346}
347
348
349static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
350{
351 return true;
352}
353
354
355#define PRINT_ALIAS_INSTR
356#include "SparcGenAsmWriter.inc"
357
358void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
359{
Nguyen Anh Quynha7264022014-08-15 18:29:17 +0800360 char *mnem, *p;
361 char instr[64]; // Sparc has no instruction this long
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800362
363 mnem = printAliasInstr(MI, O, Info);
Nguyen Anh Quynh159ddbd2014-08-15 16:35:12 +0800364 if (mnem) {
365 // fixup instruction id due to the change in alias instruction
Nguyen Anh Quynha7264022014-08-15 18:29:17 +0800366 strncpy(instr, mnem, strlen(mnem));
367 instr[strlen(mnem)] = '\0';
368 // does this contains hint with a coma?
369 p = strchr(instr, ',');
370 if (p)
371 *p = '\0'; // now instr only has instruction mnemonic
372 MCInst_setOpcodePub(MI, Sparc_map_insn(instr));
373 switch(MCInst_getOpcode(MI)) {
374 case SP_BCOND:
375 case SP_BCONDA:
376 case SP_BPICCANT:
377 case SP_BPICCNT:
378 case SP_BPXCCANT:
379 case SP_BPXCCNT:
380 case SP_TXCCri:
381 case SP_TXCCrr:
382 if (MI->csh->detail) {
383 // skip 'b', 't'
384 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1);
385 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
386 }
387 break;
388 case SP_BPFCCANT:
389 case SP_BPFCCNT:
390 if (MI->csh->detail) {
391 // skip 'fb'
392 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2);
393 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
394 }
395 break;
396 case SP_FMOVD_ICC:
397 case SP_FMOVD_XCC:
398 case SP_FMOVQ_ICC:
399 case SP_FMOVQ_XCC:
400 case SP_FMOVS_ICC:
401 case SP_FMOVS_XCC:
402 if (MI->csh->detail) {
403 // skip 'fmovd', 'fmovq', 'fmovs'
404 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5);
405 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
406 }
407 break;
408 case SP_MOVICCri:
409 case SP_MOVICCrr:
410 case SP_MOVXCCri:
411 case SP_MOVXCCrr:
412 if (MI->csh->detail) {
413 // skip 'mov'
414 MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3);
415 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
416 }
417 break;
418 case SP_V9FMOVD_FCC:
419 case SP_V9FMOVQ_FCC:
420 case SP_V9FMOVS_FCC:
421 if (MI->csh->detail) {
422 // skip 'fmovd', 'fmovq', 'fmovs'
423 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5);
424 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
425 }
426 break;
427 case SP_V9MOVFCCri:
428 case SP_V9MOVFCCrr:
429 if (MI->csh->detail) {
430 // skip 'mov'
431 MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3);
432 MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem);
433 }
434 break;
435 default:
436 break;
437 }
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800438 cs_mem_free(mnem);
Nguyen Anh Quynh159ddbd2014-08-15 16:35:12 +0800439 } else {
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800440 if (!printSparcAliasInstr(MI, O))
441 printInstruction(MI, O, NULL);
442 }
443}
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +0800444
Nguyen Anh Quynhb6f4c1d2014-11-11 07:02:13 +0800445void Sparc_addReg(MCInst *MI, int reg)
446{
447 if (MI->csh->detail) {
448 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
449 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
450 MI->flat_insn->detail->sparc.op_count++;
451 }
452}
453
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +0800454#endif