Rizin
unix-like reverse engineering framework and cli tools
SparcInstPrinter.c
Go to the documentation of this file.
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 
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 
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 
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 
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 
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 
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");
131  printMemOperand(MI, 1, O, NULL);
132  return true;
133  case SP_O7: // call $addr
134  SStream_concat0(O, "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 
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);
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(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(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(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 = 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 
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 
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 
338 
339  if (MI->csh->detail)
340  MI->flat_insn->detail->sparc.cc = (sparc_cc)CC;
341 }
342 
343 
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 
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) - 1);
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
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 
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
#define mnem(n, mn)
unsigned MCInst_getOpcode(const MCInst *inst)
Definition: MCInst.c:68
unsigned MCInst_getNumOperands(const MCInst *inst)
Definition: MCInst.c:83
MCOperand * MCInst_getOperand(MCInst *inst, unsigned i)
Definition: MCInst.c:78
bool MCOperand_isReg(const MCOperand *op)
Definition: MCInst.c:101
void MCInst_setOpcodePub(MCInst *inst, unsigned Op)
Definition: MCInst.c:63
int64_t MCOperand_getImm(MCOperand *op)
Definition: MCInst.c:128
unsigned MCOperand_getReg(const MCOperand *op)
getReg - Returns the register number.
Definition: MCInst.c:117
bool MCOperand_isImm(const MCOperand *op)
Definition: MCInst.c:106
static int32_t SignExtend32(uint32_t X, unsigned B)
Sign extend number in the bottom B bits of X to a 32-bit int. Requires 0 < B <= 32.
Definition: MathExtras.h:407
void printInt64(SStream *O, int64_t val)
Definition: SStream.c:87
void SStream_concat0(SStream *ss, const char *s)
Definition: SStream.c:31
void Sparc_printInst(MCInst *MI, SStream *O, void *Info)
void Sparc_addReg(MCInst *MI, int reg)
void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
sparc_reg Sparc_map_insn(const char *name)
sparc_hint Sparc_map_hint(const char *name)
sparc_cc Sparc_map_FCC(const char *name)
sparc_cc Sparc_map_ICC(const char *name)
sparc_reg Sparc_map_register(unsigned int r)
static const char * SPARCCondCodeToString(sparc_cc CC)
Definition: Sparc.h:23
@ CS_MODE_V9
SparcV9 mode (Sparc)
Definition: capstone.h:115
size_t csh
Definition: capstone.h:71
@ CS_OPT_ON
Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA).
Definition: capstone.h:183
#define NULL
Definition: cris-opc.c:27
cs_free_t cs_mem_free
Definition: cs.c:351
@ OS
Definition: inflate.h:24
#define reg(n)
void * p
Definition: libc.cpp:67
static const char struct stat static buf struct stat static buf static vhangup int status
Definition: sflib.h:145
#define O
Definition: rcond.c:14
static int
Definition: sfsocketcall.h:114
long int64_t
Definition: sftypes.h:32
unsigned char uint8_t
Definition: sftypes.h:31
Definition: MCInst.h:88
cs_insn * flat_insn
Definition: MCInst.h:95
cs_struct * csh
Definition: MCInst.h:97
unsigned Opcode
Definition: MCInst.h:93
uint64_t address
Definition: MCInst.h:96
Definition: SStream.h:9
bool doing_mem
Definition: cs_priv.h:70
cs_mode mode
Definition: cs_priv.h:56
cs_opt_value detail
Definition: cs_priv.h:68
@ SPARC_REG_INVALID
Definition: sparc.h:79
@ SPARC_OP_MEM
= CS_OP_MEM (Memory operand).
Definition: sparc.h:74
@ SPARC_OP_IMM
= CS_OP_IMM (Immediate operand).
Definition: sparc.h:73
@ SPARC_OP_REG
= CS_OP_REG (Register operand).
Definition: sparc.h:72
sparc_cc
Enums corresponding to Sparc condition codes, both icc's and fcc's.
Definition: sparc.h:22
@ SPARC_INS_RETL
Definition: sparc.h:491
@ SPARC_INS_JMP
Definition: sparc.h:228
@ SPARC_INS_FCMPD
Definition: sparc.h:271
@ SPARC_INS_FCMPEQ
Definition: sparc.h:479
@ SPARC_INS_CALL
Definition: sparc.h:238
@ SPARC_INS_FCMPES
Definition: sparc.h:480
@ SPARC_INS_CASX
Definition: sparc.h:239
@ SPARC_INS_FCMPQ
Definition: sparc.h:280
@ SPARC_INS_FCMPED
Definition: sparc.h:478
@ SPARC_INS_RET
Definition: sparc.h:490
@ SPARC_INS_FCMPS
Definition: sparc.h:281