blob: 4882826a2ab4d2d793682f6749c5d1ce9e09d542 [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 */
15/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2014 */
16
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +080017#ifdef CAPSTONE_HAS_SPARC
18
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080019#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "SparcInstPrinter.h"
24#include "../../MCInst.h"
25#include "../../utils.h"
26#include "../../SStream.h"
27#include "../../MCRegisterInfo.h"
28#include "../../MathExtras.h"
29#include "SparcMapping.h"
30
31#include "Sparc.h"
32
33static const char *getRegisterName(unsigned RegNo);
34static void printInstruction(MCInst *MI, SStream *O, MCRegisterInfo *MRI);
35static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier);
36static void printOperand(MCInst *MI, int opNum, SStream *O);
37
38static void set_mem_access(MCInst *MI, bool status)
39{
40 if (MI->csh->detail != CS_OPT_ON)
41 return;
42
43 MI->csh->doing_mem = status;
44
45 if (status) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070046 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM;
47 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID;
48 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080049 } else {
50 // done, create the next operand slot
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +070051 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080052 }
53}
54
Nguyen Anh Quynh64564812014-05-19 16:46:31 +080055void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +080056{
57 if (((cs_struct *)ud)->detail != CS_OPT_ON)
58 return;
59
60 // fix up some instructions
61 if (insn->id == SPARC_INS_CASX) {
62 // first op is actually a memop, not regop
63 insn->detail->sparc.operands[0].type = SPARC_OP_MEM;
64 insn->detail->sparc.operands[0].mem.base = insn->detail->sparc.operands[0].reg;
65 insn->detail->sparc.operands[0].mem.disp = 0;
66 }
67}
68
69static void printRegName(SStream *OS, unsigned RegNo)
70{
71 SStream_concat(OS, "%%%s", getRegisterName(RegNo));
72}
73
74#define GET_INSTRINFO_ENUM
75#include "SparcGenInstrInfo.inc"
76
77#define GET_REGINFO_ENUM
78#include "SparcGenRegisterInfo.inc"
79
80static bool printSparcAliasInstr(MCInst *MI, SStream *O)
81{
82 switch (MCInst_getOpcode(MI)) {
83 default: return false;
84 case SP_JMPLrr:
85 case SP_JMPLri:
86 if (MCInst_getNumOperands(MI) != 3)
87 return false;
88 if (!MCOperand_isReg(MCInst_getOperand(MI, 0)))
89 return false;
90
91 switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) {
92 default: return false;
93 case SP_G0: // jmp $addr | ret | retl
94 if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
95 MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) {
96 switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) {
97 default: break;
Nguyen Anh Quynh641be492014-03-10 17:57:04 +080098 case SP_I7: SStream_concat(O, "ret"); return true;
99 case SP_O7: SStream_concat(O, "retl"); return true;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800100 }
101 }
102
Nguyen Anh Quynh641be492014-03-10 17:57:04 +0800103 SStream_concat(O, "jmp\t");
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800104 printMemOperand(MI, 1, O, NULL);
105 return true;
106 case SP_O7: // call $addr
Nguyen Anh Quynh641be492014-03-10 17:57:04 +0800107 SStream_concat(O, "call ");
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800108 printMemOperand(MI, 1, O, NULL);
109 return true;
110 }
111 case SP_V9FCMPS:
112 case SP_V9FCMPD:
113 case SP_V9FCMPQ:
114 case SP_V9FCMPES:
115 case SP_V9FCMPED:
116 case SP_V9FCMPEQ:
117 if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) ||
118 (!MCOperand_isReg(MCInst_getOperand(MI, 0))) ||
119 (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0))
120 return false;
121 // if V8, skip printing %fcc0.
122 switch(MCInst_getOpcode(MI)) {
123 default:
Nguyen Anh Quynh641be492014-03-10 17:57:04 +0800124 case SP_V9FCMPS: SStream_concat(O, "fcmps\t"); break;
125 case SP_V9FCMPD: SStream_concat(O, "fcmpd\t"); break;
126 case SP_V9FCMPQ: SStream_concat(O, "fcmpq\t"); break;
127 case SP_V9FCMPES: SStream_concat(O, "fcmpes\t"); break;
128 case SP_V9FCMPED: SStream_concat(O, "fcmped\t"); break;
129 case SP_V9FCMPEQ: SStream_concat(O, "fcmpeq\t"); break;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800130 }
131 printOperand(MI, 1, O);
132 SStream_concat(O, ", ");
133 printOperand(MI, 2, O);
134 return true;
135 }
136}
137
138static void printOperand(MCInst *MI, int opNum, SStream *O)
139{
140 int Imm;
141 unsigned reg;
142 MCOperand *MO = MCInst_getOperand(MI, opNum);
143
144 if (MCOperand_isReg(MO)) {
145 reg = MCOperand_getReg(MO);
146 printRegName(O, reg);
147 reg = Sparc_map_register(reg);
148
149 if (MI->csh->detail) {
150 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700151 if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base)
152 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = reg;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800153 else
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700154 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = reg;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800155 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700156 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG;
157 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg;
158 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800159 }
160 }
161
162 return;
163 }
164
165 if (MCOperand_isImm(MO)) {
166 Imm = (int)MCOperand_getImm(MO);
Nguyen Anh Quynha3c9bd62014-03-26 16:22:16 +0800167 if (Imm >= 0) {
168 if (Imm > HEX_THRESHOLD)
169 SStream_concat(O, "0x%x", Imm);
170 else
171 SStream_concat(O, "%u", Imm);
172 } else {
173 if (Imm < -HEX_THRESHOLD)
174 SStream_concat(O, "-0x%x", -Imm);
175 else
176 SStream_concat(O, "-%u", -Imm);
177 }
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800178
179 if (MI->csh->detail) {
180 if (MI->csh->doing_mem) {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700181 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800182 } else {
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700183 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM;
184 MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm;
185 MI->flat_insn->detail->sparc.op_count++;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800186 }
187 }
188 }
189
190 return;
191}
192
193static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier)
194{
195 MCOperand *MO;
196
197 set_mem_access(MI, true);
198 printOperand(MI, opNum, O);
199
200 // If this is an ADD operand, emit it like normal operands.
201 if (Modifier && !strcmp(Modifier, "arith")) {
202 SStream_concat(O, ", ");
203 printOperand(MI, opNum + 1, O);
204 set_mem_access(MI, false);
205 return;
206 }
207
208 MO = MCInst_getOperand(MI, opNum + 1);
209
210 if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) {
211 set_mem_access(MI, false);
212 return; // don't print "+%g0"
213 }
214
215 if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) {
216 set_mem_access(MI, false);
217 return; // don't print "+0"
218 }
219
220 SStream_concat(O, "+");
221
222 printOperand(MI, opNum + 1, O);
223 set_mem_access(MI, false);
224}
225
226static void printCCOperand(MCInst *MI, int opNum, SStream *O)
227{
Nguyen Anh Quynh5d6383e2014-05-25 13:48:06 +0800228 int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800229
230 switch (MCInst_getOpcode(MI)) {
231 default: break;
232 case SP_FBCOND:
233 case SP_FBCONDA:
234 case SP_BPFCC:
235 case SP_BPFCCA:
236 case SP_BPFCCNT:
237 case SP_BPFCCANT:
238 case SP_MOVFCCrr: case SP_V9MOVFCCrr:
239 case SP_MOVFCCri: case SP_V9MOVFCCri:
240 case SP_FMOVS_FCC: case SP_V9FMOVS_FCC:
241 case SP_FMOVD_FCC: case SP_V9FMOVD_FCC:
242 case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC:
243 // Make sure CC is a fp conditional flag.
Nguyen Anh Quynh5d6383e2014-05-25 13:48:06 +0800244 CC = (CC < 16+256) ? (CC + 16) : CC;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800245 break;
246 }
247
248 SStream_concat(O, "%s", SPARCCondCodeToString((sparc_cc)CC));
249
250 if (MI->csh->detail)
Nguyen Anh Quynh29fd0f62014-06-09 08:00:18 +0700251 MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
Nguyen Anh Quynh05e27132014-03-10 11:58:57 +0800252}
253
254
255static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O)
256{
257 return true;
258}
259
260
261#define PRINT_ALIAS_INSTR
262#include "SparcGenAsmWriter.inc"
263
264void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
265{
266 char *mnem;
267
268 mnem = printAliasInstr(MI, O, Info);
269 if (mnem)
270 cs_mem_free(mnem);
271 else {
272 if (!printSparcAliasInstr(MI, O))
273 printInstruction(MI, O, NULL);
274 }
275}
Nguyen Anh Quynh8598a212014-05-14 11:26:41 +0800276
277#endif