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