Rizin
unix-like reverse engineering framework and cli tools
MipsInstPrinter.c
Go to the documentation of this file.
1 //===-- MipsInstPrinter.cpp - Convert Mips 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 Mips 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_MIPS
18 
19 #include <capstone/platform.h>
20 #include <stdlib.h>
21 #include <stdio.h> // debug
22 #include <string.h>
23 
24 #include "MipsInstPrinter.h"
25 #include "../../MCInst.h"
26 #include "../../utils.h"
27 #include "../../SStream.h"
28 #include "../../MCRegisterInfo.h"
29 #include "MipsMapping.h"
30 
31 #include "MipsInstPrinter.h"
32 
33 static void printUnsignedImm(MCInst *MI, int opNum, SStream *O);
34 static char *printAliasInstr(MCInst *MI, SStream *O, void *info);
35 static char *printAlias(MCInst *MI, SStream *OS);
36 
37 // These enumeration declarations were originally in MipsInstrInfo.h but
38 // had to be moved here to avoid circular dependencies between
39 // LLVMMipsCodeGen and LLVMMipsAsmPrinter.
40 
41 // Mips Condition Codes
42 typedef enum Mips_CondCode {
43  // To be used with float branch True
44  Mips_FCOND_F,
45  Mips_FCOND_UN,
46  Mips_FCOND_OEQ,
47  Mips_FCOND_UEQ,
48  Mips_FCOND_OLT,
49  Mips_FCOND_ULT,
50  Mips_FCOND_OLE,
51  Mips_FCOND_ULE,
52  Mips_FCOND_SF,
53  Mips_FCOND_NGLE,
54  Mips_FCOND_SEQ,
55  Mips_FCOND_NGL,
56  Mips_FCOND_LT,
57  Mips_FCOND_NGE,
58  Mips_FCOND_LE,
59  Mips_FCOND_NGT,
60 
61  // To be used with float branch False
62  // This conditions have the same mnemonic as the
63  // above ones, but are used with a branch False;
64  Mips_FCOND_T,
65  Mips_FCOND_OR,
66  Mips_FCOND_UNE,
67  Mips_FCOND_ONE,
68  Mips_FCOND_UGE,
69  Mips_FCOND_OGE,
70  Mips_FCOND_UGT,
71  Mips_FCOND_OGT,
72  Mips_FCOND_ST,
73  Mips_FCOND_GLE,
74  Mips_FCOND_SNE,
75  Mips_FCOND_GL,
76  Mips_FCOND_NLT,
77  Mips_FCOND_GE,
78  Mips_FCOND_NLE,
79  Mips_FCOND_GT
80 } Mips_CondCode;
81 
82 #define GET_INSTRINFO_ENUM
83 #include "MipsGenInstrInfo.inc"
84 
85 static const char *getRegisterName(unsigned RegNo);
86 static void printInstruction(MCInst *MI, SStream *O, const MCRegisterInfo *MRI);
87 
88 static void set_mem_access(MCInst *MI, bool status)
89 {
90  MI->csh->doing_mem = status;
91 
92  if (MI->csh->detail != CS_OPT_ON)
93  return;
94 
95  if (status) {
96  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_MEM;
97  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = MIPS_REG_INVALID;
98  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = 0;
99  } else {
100  // done, create the next operand slot
101  MI->flat_insn->detail->mips.op_count++;
102  }
103 }
104 
105 static bool isReg(MCInst *MI, unsigned OpNo, unsigned R)
106 {
107  return (MCOperand_isReg(MCInst_getOperand(MI, OpNo)) &&
108  MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == R);
109 }
110 
111 static const char* MipsFCCToString(Mips_CondCode CC)
112 {
113  switch (CC) {
114  default: return 0; // never reach
115  case Mips_FCOND_F:
116  case Mips_FCOND_T: return "f";
117  case Mips_FCOND_UN:
118  case Mips_FCOND_OR: return "un";
119  case Mips_FCOND_OEQ:
120  case Mips_FCOND_UNE: return "eq";
121  case Mips_FCOND_UEQ:
122  case Mips_FCOND_ONE: return "ueq";
123  case Mips_FCOND_OLT:
124  case Mips_FCOND_UGE: return "olt";
125  case Mips_FCOND_ULT:
126  case Mips_FCOND_OGE: return "ult";
127  case Mips_FCOND_OLE:
128  case Mips_FCOND_UGT: return "ole";
129  case Mips_FCOND_ULE:
130  case Mips_FCOND_OGT: return "ule";
131  case Mips_FCOND_SF:
132  case Mips_FCOND_ST: return "sf";
133  case Mips_FCOND_NGLE:
134  case Mips_FCOND_GLE: return "ngle";
135  case Mips_FCOND_SEQ:
136  case Mips_FCOND_SNE: return "seq";
137  case Mips_FCOND_NGL:
138  case Mips_FCOND_GL: return "ngl";
139  case Mips_FCOND_LT:
140  case Mips_FCOND_NLT: return "lt";
141  case Mips_FCOND_NGE:
142  case Mips_FCOND_GE: return "nge";
143  case Mips_FCOND_LE:
144  case Mips_FCOND_NLE: return "le";
145  case Mips_FCOND_NGT:
146  case Mips_FCOND_GT: return "ngt";
147  }
148 }
149 
150 static void printRegName(SStream *OS, unsigned RegNo)
151 {
152  SStream_concat(OS, "$%s", getRegisterName(RegNo));
153 }
154 
155 void Mips_printInst(MCInst *MI, SStream *O, void *info)
156 {
157  char *mnem;
158 
159  switch (MCInst_getOpcode(MI)) {
160  default: break;
161  case Mips_Save16:
162  case Mips_SaveX16:
163  case Mips_Restore16:
164  case Mips_RestoreX16:
165  return;
166  }
167 
168  // Try to print any aliases first.
169  mnem = printAliasInstr(MI, O, info);
170  if (!mnem) {
171  mnem = printAlias(MI, O);
172  if (!mnem) {
173  printInstruction(MI, O, NULL);
174  }
175  }
176 
177  if (mnem) {
178  // fixup instruction id due to the change in alias instruction
180  cs_mem_free(mnem);
181  }
182 }
183 
184 static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
185 {
186  MCOperand *Op;
187 
188  if (OpNo >= MI->size)
189  return;
190 
191  Op = MCInst_getOperand(MI, OpNo);
192  if (MCOperand_isReg(Op)) {
193  unsigned int reg = MCOperand_getReg(Op);
194  printRegName(O, reg);
196  if (MI->csh->detail) {
197  if (MI->csh->doing_mem) {
198  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.base = reg;
199  } else {
200  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_REG;
201  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].reg = reg;
202  MI->flat_insn->detail->mips.op_count++;
203  }
204  }
205  } else if (MCOperand_isImm(Op)) {
207  if (MI->csh->doing_mem) {
208  if (imm) { // only print Imm offset if it is not 0
209  printInt64(O, imm);
210  }
211  if (MI->csh->detail)
212  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].mem.disp = imm;
213  } else {
214  printInt64(O, imm);
215 
216  if (MI->csh->detail) {
217  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
218  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;
219  MI->flat_insn->detail->mips.op_count++;
220  }
221  }
222  }
223 }
224 
225 static void printUnsignedImm(MCInst *MI, int opNum, SStream *O)
226 {
227  MCOperand *MO = MCInst_getOperand(MI, opNum);
228  if (MCOperand_isImm(MO)) {
230  printInt64(O, imm);
231 
232  if (MI->csh->detail) {
233  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
234  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = (unsigned short int)imm;
235  MI->flat_insn->detail->mips.op_count++;
236  }
237  } else
238  printOperand(MI, opNum, O);
239 }
240 
241 static void printUnsignedImm8(MCInst *MI, int opNum, SStream *O)
242 {
243  MCOperand *MO = MCInst_getOperand(MI, opNum);
244  if (MCOperand_isImm(MO)) {
246  if (imm > HEX_THRESHOLD)
247  SStream_concat(O, "0x%x", imm);
248  else
249  SStream_concat(O, "%u", imm);
250  if (MI->csh->detail) {
251  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_IMM;
252  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].imm = imm;
253  MI->flat_insn->detail->mips.op_count++;
254  }
255  } else
256  printOperand(MI, opNum, O);
257 }
258 
259 static void printMemOperand(MCInst *MI, int opNum, SStream *O)
260 {
261  // Load/Store memory operands -- imm($reg)
262  // If PIC target the target is loaded as the
263  // pattern lw $25,%call16($28)
264 
265  // opNum can be invalid if instruction had reglist as operand.
266  // MemOperand is always last operand of instruction (base + offset).
267  switch (MCInst_getOpcode(MI)) {
268  default:
269  break;
270  case Mips_SWM32_MM:
271  case Mips_LWM32_MM:
272  case Mips_SWM16_MM:
273  case Mips_LWM16_MM:
274  opNum = MCInst_getNumOperands(MI) - 2;
275  break;
276  }
277 
278  set_mem_access(MI, true);
279  printOperand(MI, opNum + 1, O);
280  SStream_concat0(O, "(");
281  printOperand(MI, opNum, O);
282  SStream_concat0(O, ")");
283  set_mem_access(MI, false);
284 }
285 
286 // TODO???
287 static void printMemOperandEA(MCInst *MI, int opNum, SStream *O)
288 {
289  // when using stack locations for not load/store instructions
290  // print the same way as all normal 3 operand instructions.
291  printOperand(MI, opNum, O);
292  SStream_concat0(O, ", ");
293  printOperand(MI, opNum + 1, O);
294  return;
295 }
296 
297 static void printFCCOperand(MCInst *MI, int opNum, SStream *O)
298 {
299  MCOperand *MO = MCInst_getOperand(MI, opNum);
300  SStream_concat0(O, MipsFCCToString((Mips_CondCode)MCOperand_getImm(MO)));
301 }
302 
303 static void printRegisterPair(MCInst *MI, int opNum, SStream *O)
304 {
305  printRegName(O, MCOperand_getReg(MCInst_getOperand(MI, opNum)));
306 }
307 
308 static char *printAlias1(const char *Str, MCInst *MI, unsigned OpNo, SStream *OS)
309 {
310  SStream_concat(OS, "%s\t", Str);
311  printOperand(MI, OpNo, OS);
312  return cs_strdup(Str);
313 }
314 
315 static char *printAlias2(const char *Str, MCInst *MI,
316  unsigned OpNo0, unsigned OpNo1, SStream *OS)
317 {
318  char *tmp;
319 
320  tmp = printAlias1(Str, MI, OpNo0, OS);
321  SStream_concat0(OS, ", ");
322  printOperand(MI, OpNo1, OS);
323 
324  return tmp;
325 }
326 
327 #define GET_REGINFO_ENUM
328 #include "MipsGenRegisterInfo.inc"
329 
330 static char *printAlias(MCInst *MI, SStream *OS)
331 {
332  switch (MCInst_getOpcode(MI)) {
333  case Mips_BEQ:
334  case Mips_BEQ_MM:
335  // beq $zero, $zero, $L2 => b $L2
336  // beq $r0, $zero, $L2 => beqz $r0, $L2
337  if (isReg(MI, 0, Mips_ZERO) && isReg(MI, 1, Mips_ZERO))
338  return printAlias1("b", MI, 2, OS);
339  if (isReg(MI, 1, Mips_ZERO))
340  return printAlias2("beqz", MI, 0, 2, OS);
341  return NULL;
342  case Mips_BEQ64:
343  // beq $r0, $zero, $L2 => beqz $r0, $L2
344  if (isReg(MI, 1, Mips_ZERO_64))
345  return printAlias2("beqz", MI, 0, 2, OS);
346  return NULL;
347  case Mips_BNE:
348  // bne $r0, $zero, $L2 => bnez $r0, $L2
349  if (isReg(MI, 1, Mips_ZERO))
350  return printAlias2("bnez", MI, 0, 2, OS);
351  return NULL;
352  case Mips_BNE64:
353  // bne $r0, $zero, $L2 => bnez $r0, $L2
354  if (isReg(MI, 1, Mips_ZERO_64))
355  return printAlias2("bnez", MI, 0, 2, OS);
356  return NULL;
357  case Mips_BGEZAL:
358  // bgezal $zero, $L1 => bal $L1
359  if (isReg(MI, 0, Mips_ZERO))
360  return printAlias1("bal", MI, 1, OS);
361  return NULL;
362  case Mips_BC1T:
363  // bc1t $fcc0, $L1 => bc1t $L1
364  if (isReg(MI, 0, Mips_FCC0))
365  return printAlias1("bc1t", MI, 1, OS);
366  return NULL;
367  case Mips_BC1F:
368  // bc1f $fcc0, $L1 => bc1f $L1
369  if (isReg(MI, 0, Mips_FCC0))
370  return printAlias1("bc1f", MI, 1, OS);
371  return NULL;
372  case Mips_JALR:
373  // jalr $ra, $r1 => jalr $r1
374  if (isReg(MI, 0, Mips_RA))
375  return printAlias1("jalr", MI, 1, OS);
376  return NULL;
377  case Mips_JALR64:
378  // jalr $ra, $r1 => jalr $r1
379  if (isReg(MI, 0, Mips_RA_64))
380  return printAlias1("jalr", MI, 1, OS);
381  return NULL;
382  case Mips_NOR:
383  case Mips_NOR_MM:
384  // nor $r0, $r1, $zero => not $r0, $r1
385  if (isReg(MI, 2, Mips_ZERO))
386  return printAlias2("not", MI, 0, 1, OS);
387  return NULL;
388  case Mips_NOR64:
389  // nor $r0, $r1, $zero => not $r0, $r1
390  if (isReg(MI, 2, Mips_ZERO_64))
391  return printAlias2("not", MI, 0, 1, OS);
392  return NULL;
393  case Mips_OR:
394  // or $r0, $r1, $zero => move $r0, $r1
395  if (isReg(MI, 2, Mips_ZERO))
396  return printAlias2("move", MI, 0, 1, OS);
397  return NULL;
398  default: return NULL;
399  }
400 }
401 
402 static void printRegisterList(MCInst *MI, int opNum, SStream *O)
403 {
404  int i, e, reg;
405 
406  // - 2 because register List is always first operand of instruction and it is
407  // always followed by memory operand (base + offset).
408  for (i = opNum, e = MCInst_getNumOperands(MI) - 2; i != e; ++i) {
409  if (i != opNum)
410  SStream_concat0(O, ", ");
412  printRegName(O, reg);
413  if (MI->csh->detail) {
414  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].type = MIPS_OP_REG;
415  MI->flat_insn->detail->mips.operands[MI->flat_insn->detail->mips.op_count].reg = reg;
416  MI->flat_insn->detail->mips.op_count++;
417  }
418  }
419 }
420 
421 #define PRINT_ALIAS_INSTR
422 #include "MipsGenAsmWriter.inc"
423 
424 #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
void Mips_printInst(MCInst *MI, SStream *O, void *info)
mips_reg Mips_map_register(unsigned int r)
mips_reg Mips_map_insn(const char *name)
void printInt64(SStream *O, int64_t val)
Definition: SStream.c:87
void SStream_concat(SStream *ss, const char *fmt,...)
Definition: SStream.c:45
void SStream_concat0(SStream *ss, const char *s)
Definition: SStream.c:31
#define e(frag)
#define imm
lzma_index ** i
Definition: index.h:629
#define R(x, b, m)
Definition: arc.h:168
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
@ 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)
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
uint8_t size
Definition: MCInst.h:90
cs_struct * csh
Definition: MCInst.h:97
Definition: SStream.h:9
bool doing_mem
Definition: cs_priv.h:70
cs_opt_value detail
Definition: cs_priv.h:68
@ MIPS_OP_REG
= CS_OP_REG (Register operand).
Definition: mips.h:24
@ MIPS_OP_IMM
= CS_OP_IMM (Immediate operand).
Definition: mips.h:25
@ MIPS_OP_MEM
= CS_OP_MEM (Memory operand).
Definition: mips.h:26
@ MIPS_REG_INVALID
Definition: mips.h:31
char * cs_strdup(const char *str)
Definition: utils.c:92
#define HEX_THRESHOLD
Definition: utils.h:16