• 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-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