diff options
Diffstat (limited to 'capstone/arch/Sparc/SparcInstPrinter.c')
-rw-r--r-- | capstone/arch/Sparc/SparcInstPrinter.c | 449 |
1 files changed, 449 insertions, 0 deletions
diff --git a/capstone/arch/Sparc/SparcInstPrinter.c b/capstone/arch/Sparc/SparcInstPrinter.c new file mode 100644 index 000000000..da8318744 --- /dev/null +++ b/capstone/arch/Sparc/SparcInstPrinter.c @@ -0,0 +1,449 @@ +//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This class prints an Sparc MCInst to a .s file. +// +//===----------------------------------------------------------------------===// + +/* Capstone Disassembly Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */ + +#ifdef CAPSTONE_HAS_SPARC + +#ifdef _MSC_VER +#define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64) +#pragma warning(disable:28719) // disable MSVC's warning on strncpy() +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "SparcInstPrinter.h" +#include "../../MCInst.h" +#include "../../utils.h" +#include "../../SStream.h" +#include "../../MCRegisterInfo.h" +#include "../../MathExtras.h" +#include "SparcMapping.h" + +#include "Sparc.h" + +static const char *getRegisterName(unsigned RegNo); +static void printInstruction(MCInst *MI, SStream *O, const MCRegisterInfo *MRI); +static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier); +static void printOperand(MCInst *MI, int opNum, SStream *O); + +static void Sparc_add_hint(MCInst *MI, unsigned int hint) +{ + if (MI->csh->detail) { + MI->flat_insn->detail->sparc.hint = hint; + } +} + +static void Sparc_add_reg(MCInst *MI, unsigned int reg) +{ + if (MI->csh->detail) { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg; + MI->flat_insn->detail->sparc.op_count++; + } +} + +static void set_mem_access(MCInst *MI, bool status) +{ + if (MI->csh->detail != CS_OPT_ON) + return; + + MI->csh->doing_mem = status; + + if (status) { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_MEM; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = SPARC_REG_INVALID; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = 0; + } else { + // done, create the next operand slot + MI->flat_insn->detail->sparc.op_count++; + } +} + +void Sparc_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) +{ + if (((cs_struct *)ud)->detail != CS_OPT_ON) + return; + + // fix up some instructions + if (insn->id == SPARC_INS_CASX) { + // first op is actually a memop, not regop + insn->detail->sparc.operands[0].type = SPARC_OP_MEM; + insn->detail->sparc.operands[0].mem.base = (uint8_t)insn->detail->sparc.operands[0].reg; + insn->detail->sparc.operands[0].mem.disp = 0; + } +} + +static void printRegName(SStream *OS, unsigned RegNo) +{ + SStream_concat0(OS, "%"); + SStream_concat0(OS, getRegisterName(RegNo)); +} + +#define GET_INSTRINFO_ENUM +#include "SparcGenInstrInfo.inc" + +#define GET_REGINFO_ENUM +#include "SparcGenRegisterInfo.inc" + +static bool printSparcAliasInstr(MCInst *MI, SStream *O) +{ + switch (MCInst_getOpcode(MI)) { + default: return false; + case SP_JMPLrr: + case SP_JMPLri: + if (MCInst_getNumOperands(MI) != 3) + return false; + if (!MCOperand_isReg(MCInst_getOperand(MI, 0))) + return false; + + switch (MCOperand_getReg(MCInst_getOperand(MI, 0))) { + default: return false; + case SP_G0: // jmp $addr | ret | retl + if (MCOperand_isImm(MCInst_getOperand(MI, 2)) && + MCOperand_getImm(MCInst_getOperand(MI, 2)) == 8) { + switch(MCOperand_getReg(MCInst_getOperand(MI, 1))) { + default: break; + case SP_I7: SStream_concat0(O, "ret"); MCInst_setOpcodePub(MI, SPARC_INS_RET); return true; + case SP_O7: SStream_concat0(O, "retl"); MCInst_setOpcodePub(MI, SPARC_INS_RETL); return true; + } + } + + SStream_concat0(O, "jmp\t"); + MCInst_setOpcodePub(MI, SPARC_INS_JMP); + printMemOperand(MI, 1, O, NULL); + return true; + case SP_O7: // call $addr + SStream_concat0(O, "call "); + MCInst_setOpcodePub(MI, SPARC_INS_CALL); + printMemOperand(MI, 1, O, NULL); + return true; + } + case SP_V9FCMPS: + case SP_V9FCMPD: + case SP_V9FCMPQ: + case SP_V9FCMPES: + case SP_V9FCMPED: + case SP_V9FCMPEQ: + if (MI->csh->mode & CS_MODE_V9 || (MCInst_getNumOperands(MI) != 3) || + (!MCOperand_isReg(MCInst_getOperand(MI, 0))) || + (MCOperand_getReg(MCInst_getOperand(MI, 0)) != SP_FCC0)) + return false; + // if V8, skip printing %fcc0. + switch(MCInst_getOpcode(MI)) { + default: + case SP_V9FCMPS: SStream_concat0(O, "fcmps\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPS); break; + case SP_V9FCMPD: SStream_concat0(O, "fcmpd\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPD); break; + case SP_V9FCMPQ: SStream_concat0(O, "fcmpq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPQ); break; + case SP_V9FCMPES: SStream_concat0(O, "fcmpes\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPES); break; + case SP_V9FCMPED: SStream_concat0(O, "fcmped\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPED); break; + case SP_V9FCMPEQ: SStream_concat0(O, "fcmpeq\t"); MCInst_setOpcodePub(MI, SPARC_INS_FCMPEQ); break; + } + printOperand(MI, 1, O); + SStream_concat0(O, ", "); + printOperand(MI, 2, O); + return true; + } +} + +static void printOperand(MCInst *MI, int opNum, SStream *O) +{ + int64_t Imm; + unsigned reg; + MCOperand *MO = MCInst_getOperand(MI, opNum); + + if (MCOperand_isReg(MO)) { + reg = MCOperand_getReg(MO); + printRegName(O, reg); + reg = Sparc_map_register(reg); + + if (MI->csh->detail) { + if (MI->csh->doing_mem) { + if (MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base) + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.index = (uint8_t)reg; + else + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.base = (uint8_t)reg; + } else { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg; + MI->flat_insn->detail->sparc.op_count++; + } + } + + return; + } + + if (MCOperand_isImm(MO)) { + Imm = (int)MCOperand_getImm(MO); + + // Conditional branches displacements needs to be signextended to be + // able to jump backwards. + // + // Displacements are measured as the number of instructions forward or + // backward, so they need to be multiplied by 4 + switch (MI->Opcode) { + case SP_CALL: + // Imm = SignExtend32(Imm, 30); + Imm += MI->address; + break; + + // Branch on integer condition with prediction (BPcc) + // Branch on floating point condition with prediction (FBPfcc) + case SP_BPICC: + case SP_BPICCA: + case SP_BPICCANT: + case SP_BPICCNT: + case SP_BPXCC: + case SP_BPXCCA: + case SP_BPXCCANT: + case SP_BPXCCNT: + case SP_BPFCC: + case SP_BPFCCA: + case SP_BPFCCANT: + case SP_BPFCCNT: + Imm = SignExtend32(Imm, 19); + Imm = MI->address + Imm * 4; + break; + + // Branch on integer condition (Bicc) + // Branch on floating point condition (FBfcc) + case SP_BA: + case SP_BCOND: + case SP_BCONDA: + case SP_FBCOND: + case SP_FBCONDA: + Imm = SignExtend32(Imm, 22); + Imm = MI->address + Imm * 4; + break; + + // Branch on integer register with prediction (BPr) + case SP_BPGEZapn: + case SP_BPGEZapt: + case SP_BPGEZnapn: + case SP_BPGEZnapt: + case SP_BPGZapn: + case SP_BPGZapt: + case SP_BPGZnapn: + case SP_BPGZnapt: + case SP_BPLEZapn: + case SP_BPLEZapt: + case SP_BPLEZnapn: + case SP_BPLEZnapt: + case SP_BPLZapn: + case SP_BPLZapt: + case SP_BPLZnapn: + case SP_BPLZnapt: + case SP_BPNZapn: + case SP_BPNZapt: + case SP_BPNZnapn: + case SP_BPNZnapt: + case SP_BPZapn: + case SP_BPZapt: + case SP_BPZnapn: + case SP_BPZnapt: + Imm = SignExtend32(Imm, 16); + Imm = MI->address + Imm * 4; + break; + } + + printInt64(O, Imm); + + if (MI->csh->detail) { + if (MI->csh->doing_mem) { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].mem.disp = Imm; + } else { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_IMM; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].imm = Imm; + MI->flat_insn->detail->sparc.op_count++; + } + } + } + + return; +} + +static void printMemOperand(MCInst *MI, int opNum, SStream *O, const char *Modifier) +{ + MCOperand *MO; + + set_mem_access(MI, true); + printOperand(MI, opNum, O); + + // If this is an ADD operand, emit it like normal operands. + if (Modifier && !strcmp(Modifier, "arith")) { + SStream_concat0(O, ", "); + printOperand(MI, opNum + 1, O); + set_mem_access(MI, false); + return; + } + + MO = MCInst_getOperand(MI, opNum + 1); + + if (MCOperand_isReg(MO) && (MCOperand_getReg(MO) == SP_G0)) { + set_mem_access(MI, false); + return; // don't print "+%g0" + } + + if (MCOperand_isImm(MO) && (MCOperand_getImm(MO) == 0)) { + set_mem_access(MI, false); + return; // don't print "+0" + } + + SStream_concat0(O, "+"); // qq + + printOperand(MI, opNum + 1, O); + set_mem_access(MI, false); +} + +static void printCCOperand(MCInst *MI, int opNum, SStream *O) +{ + int CC = (int)MCOperand_getImm(MCInst_getOperand(MI, opNum)) + 256; + + switch (MCInst_getOpcode(MI)) { + default: break; + case SP_FBCOND: + case SP_FBCONDA: + case SP_BPFCC: + case SP_BPFCCA: + case SP_BPFCCNT: + case SP_BPFCCANT: + case SP_MOVFCCrr: case SP_V9MOVFCCrr: + case SP_MOVFCCri: case SP_V9MOVFCCri: + case SP_FMOVS_FCC: case SP_V9FMOVS_FCC: + case SP_FMOVD_FCC: case SP_V9FMOVD_FCC: + case SP_FMOVQ_FCC: case SP_V9FMOVQ_FCC: + // Make sure CC is a fp conditional flag. + CC = (CC < 16+256) ? (CC + 16) : CC; + break; + } + + SStream_concat0(O, SPARCCondCodeToString((sparc_cc)CC)); + + if (MI->csh->detail) + MI->flat_insn->detail->sparc.cc = (sparc_cc)CC; +} + + +static bool printGetPCX(MCInst *MI, unsigned opNum, SStream *O) +{ + return true; +} + + +#define PRINT_ALIAS_INSTR +#include "SparcGenAsmWriter.inc" + +void Sparc_printInst(MCInst *MI, SStream *O, void *Info) +{ + char *mnem, *p; + char instr[64]; // Sparc has no instruction this long + + mnem = printAliasInstr(MI, O, Info); + if (mnem) { + // fixup instruction id due to the change in alias instruction + strncpy(instr, mnem, sizeof(instr)); + instr[sizeof(instr) - 1] = '\0'; + // does this contains hint with a coma? + p = strchr(instr, ','); + if (p) + *p = '\0'; // now instr only has instruction mnemonic + MCInst_setOpcodePub(MI, Sparc_map_insn(instr)); + switch(MCInst_getOpcode(MI)) { + case SP_BCOND: + case SP_BCONDA: + case SP_BPICCANT: + case SP_BPICCNT: + case SP_BPXCCANT: + case SP_BPXCCNT: + case SP_TXCCri: + case SP_TXCCrr: + if (MI->csh->detail) { + // skip 'b', 't' + MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 1); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + case SP_BPFCCANT: + case SP_BPFCCNT: + if (MI->csh->detail) { + // skip 'fb' + MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 2); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + case SP_FMOVD_ICC: + case SP_FMOVD_XCC: + case SP_FMOVQ_ICC: + case SP_FMOVQ_XCC: + case SP_FMOVS_ICC: + case SP_FMOVS_XCC: + if (MI->csh->detail) { + // skip 'fmovd', 'fmovq', 'fmovs' + MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 5); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + case SP_MOVICCri: + case SP_MOVICCrr: + case SP_MOVXCCri: + case SP_MOVXCCrr: + if (MI->csh->detail) { + // skip 'mov' + MI->flat_insn->detail->sparc.cc = Sparc_map_ICC(instr + 3); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + case SP_V9FMOVD_FCC: + case SP_V9FMOVQ_FCC: + case SP_V9FMOVS_FCC: + if (MI->csh->detail) { + // skip 'fmovd', 'fmovq', 'fmovs' + MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 5); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + case SP_V9MOVFCCri: + case SP_V9MOVFCCrr: + if (MI->csh->detail) { + // skip 'mov' + MI->flat_insn->detail->sparc.cc = Sparc_map_FCC(instr + 3); + MI->flat_insn->detail->sparc.hint = Sparc_map_hint(mnem); + } + break; + default: + break; + } + cs_mem_free(mnem); + } else { + if (!printSparcAliasInstr(MI, O)) + printInstruction(MI, O, NULL); + } +} + +void Sparc_addReg(MCInst *MI, int reg) +{ + if (MI->csh->detail) { + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].type = SPARC_OP_REG; + MI->flat_insn->detail->sparc.operands[MI->flat_insn->detail->sparc.op_count].reg = reg; + MI->flat_insn->detail->sparc.op_count++; + } +} + +#endif |