aboutsummaryrefslogtreecommitdiffstats
path: root/capstone/arch/PowerPC/PPCInstPrinter.c
diff options
context:
space:
mode:
Diffstat (limited to 'capstone/arch/PowerPC/PPCInstPrinter.c')
-rw-r--r--capstone/arch/PowerPC/PPCInstPrinter.c1192
1 files changed, 1192 insertions, 0 deletions
diff --git a/capstone/arch/PowerPC/PPCInstPrinter.c b/capstone/arch/PowerPC/PPCInstPrinter.c
new file mode 100644
index 000000000..22eef4ee1
--- /dev/null
+++ b/capstone/arch/PowerPC/PPCInstPrinter.c
@@ -0,0 +1,1192 @@
+//===-- PPCInstPrinter.cpp - Convert PPC 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 PPC MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+/* Capstone Disassembly Engine */
+/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */
+
+#ifdef CAPSTONE_HAS_POWERPC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "PPCInstPrinter.h"
+#include "PPCPredicates.h"
+#include "../../MCInst.h"
+#include "../../utils.h"
+#include "../../SStream.h"
+#include "../../MCRegisterInfo.h"
+#include "../../MathExtras.h"
+#include "PPCMapping.h"
+
+#ifndef CAPSTONE_DIET
+static const char *getRegisterName(unsigned RegNo);
+#endif
+
+static void printOperand(MCInst *MI, unsigned OpNo, SStream *O);
+static void printInstruction(MCInst *MI, SStream *O);
+static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O);
+static char *printAliasInstr(MCInst *MI, SStream *OS, MCRegisterInfo *MRI);
+static char *printAliasBcc(MCInst *MI, SStream *OS, void *info);
+static void printCustomAliasOperand(MCInst *MI, unsigned OpIdx,
+ unsigned PrintMethodIdx, SStream *OS);
+
+#if 0
+static void printRegName(SStream *OS, unsigned RegNo)
+{
+ char *RegName = getRegisterName(RegNo);
+
+ if (RegName[0] == 'q' /* QPX */) {
+ // The system toolchain on the BG/Q does not understand QPX register names
+ // in .cfi_* directives, so print the name of the floating-point
+ // subregister instead.
+ RegName[0] = 'f';
+ }
+
+ SStream_concat0(OS, RegName);
+}
+#endif
+
+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->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_MEM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = PPC_REG_INVALID;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = 0;
+ } else {
+ // done, create the next operand slot
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+void PPC_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci)
+{
+ if (((cs_struct *)ud)->detail != CS_OPT_ON)
+ return;
+
+ // check if this insn has branch hint
+ if (strrchr(insn_asm, '+') != NULL && !strstr(insn_asm, ".+")) {
+ insn->detail->ppc.bh = PPC_BH_PLUS;
+ } else if (strrchr(insn_asm, '-') != NULL) {
+ insn->detail->ppc.bh = PPC_BH_MINUS;
+ }
+
+ if (strrchr(insn_asm, '.') != NULL) {
+ insn->detail->ppc.update_cr0 = true;
+ }
+}
+
+#define GET_INSTRINFO_ENUM
+#include "PPCGenInstrInfo.inc"
+
+#define GET_REGINFO_ENUM
+#include "PPCGenRegisterInfo.inc"
+
+static void op_addBC(MCInst *MI, unsigned int bc)
+{
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.bc = (ppc_bc)bc;
+ }
+}
+
+#define CREQ (0)
+#define CRGT (1)
+#define CRLT (2)
+#define CRUN (3)
+
+static int getBICRCond(int bi)
+{
+ return (bi - PPC_CR0EQ) >> 3;
+}
+
+static int getBICR(int bi)
+{
+ return ((bi - PPC_CR0EQ) & 7) + PPC_CR0;
+}
+
+static void op_addReg(MCInst *MI, unsigned int reg)
+{
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void add_CRxx(MCInst *MI, ppc_reg reg)
+{
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static char *printAliasBcc(MCInst *MI, SStream *OS, void *info)
+{
+#define GETREGCLASS_CONTAIN(_class, _reg) MCRegisterClass_contains(MCRegisterInfo_getRegClass(MRI, _class), MCOperand_getReg(MCInst_getOperand(MI, _reg)))
+ SStream ss;
+ const char *opCode;
+ char *tmp, *AsmMnem, *AsmOps, *c;
+ int OpIdx, PrintMethodIdx;
+ int decCtr = false, needComma = false;
+ MCRegisterInfo *MRI = (MCRegisterInfo *)info;
+
+ SStream_Init(&ss);
+
+ switch (MCInst_getOpcode(MI)) {
+ default: return NULL;
+ case PPC_gBC:
+ opCode = "b%s";
+ break;
+ case PPC_gBCA:
+ opCode = "b%sa";
+ break;
+ case PPC_gBCCTR:
+ opCode = "b%sctr";
+ break;
+ case PPC_gBCCTRL:
+ opCode = "b%sctrl";
+ break;
+ case PPC_gBCL:
+ opCode = "b%sl";
+ break;
+ case PPC_gBCLA:
+ opCode = "b%sla";
+ break;
+ case PPC_gBCLR:
+ opCode = "b%slr";
+ break;
+ case PPC_gBCLRL:
+ opCode = "b%slrl";
+ break;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) {
+ SStream_concat(&ss, opCode, "dnzf");
+ decCtr = true;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 2) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 3)) {
+ SStream_concat(&ss, opCode, "dzf");
+ decCtr = true;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 4) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 7) &&
+ MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
+ GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
+ int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
+
+ switch(cr) {
+ case CREQ:
+ SStream_concat(&ss, opCode, "ne");
+ break;
+ case CRGT:
+ SStream_concat(&ss, opCode, "le");
+ break;
+ case CRLT:
+ SStream_concat(&ss, opCode, "ge");
+ break;
+ case CRUN:
+ SStream_concat(&ss, opCode, "ns");
+ break;
+ }
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
+ SStream_concat0(&ss, "-");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
+ SStream_concat0(&ss, "+");
+
+ decCtr = false;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 8) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 9)) {
+ SStream_concat(&ss, opCode, "dnzt");
+ decCtr = true;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 10) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 11)) {
+ SStream_concat(&ss, opCode, "dzt");
+ decCtr = true;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 15) &&
+ MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
+ GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1)) {
+ int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
+
+ switch(cr) {
+ case CREQ:
+ SStream_concat(&ss, opCode, "eq");
+ break;
+ case CRGT:
+ SStream_concat(&ss, opCode, "gt");
+ break;
+ case CRLT:
+ SStream_concat(&ss, opCode, "lt");
+ break;
+ case CRUN:
+ SStream_concat(&ss, opCode, "so");
+ break;
+ }
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
+ SStream_concat0(&ss, "-");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15)
+ SStream_concat0(&ss, "+");
+
+ decCtr = false;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 16)) {
+ SStream_concat(&ss, opCode, "dnz");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 24)
+ SStream_concat0(&ss, "-");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 25)
+ SStream_concat0(&ss, "+");
+
+ needComma = false;
+ }
+
+ if (MCInst_getNumOperands(MI) == 3 &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ ((MCOperand_getImm(MCInst_getOperand(MI, 0)) & 0x12)== 18)) {
+ SStream_concat(&ss, opCode, "dz");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 26)
+ SStream_concat0(&ss, "-");
+
+ if (MCOperand_getImm(MCInst_getOperand(MI, 0)) == 27)
+ SStream_concat0(&ss, "+");
+
+ needComma = false;
+ }
+
+ if (MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
+ GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 1) &&
+ MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
+ (MCOperand_getImm(MCInst_getOperand(MI, 0)) < 16)) {
+ int cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1)));
+
+ if (decCtr) {
+ int cd;
+ needComma = true;
+ SStream_concat0(&ss, " ");
+
+ if (cr > PPC_CR0) {
+ SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0);
+ }
+
+ cd = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
+ switch(cd) {
+ case CREQ:
+ SStream_concat0(&ss, "eq");
+ if (cr <= PPC_CR0)
+ add_CRxx(MI, PPC_REG_CR0EQ);
+ op_addBC(MI, PPC_BC_EQ);
+ break;
+ case CRGT:
+ SStream_concat0(&ss, "gt");
+ if (cr <= PPC_CR0)
+ add_CRxx(MI, PPC_REG_CR0GT);
+ op_addBC(MI, PPC_BC_GT);
+ break;
+ case CRLT:
+ SStream_concat0(&ss, "lt");
+ if (cr <= PPC_CR0)
+ add_CRxx(MI, PPC_REG_CR0LT);
+ op_addBC(MI, PPC_BC_LT);
+ break;
+ case CRUN:
+ SStream_concat0(&ss, "so");
+ if (cr <= PPC_CR0)
+ add_CRxx(MI, PPC_REG_CR0UN);
+ op_addBC(MI, PPC_BC_SO);
+ break;
+ }
+
+ if (cr > PPC_CR0) {
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = MCOperand_getReg(MCInst_getOperand(MI, 1));
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+ }
+ } else {
+ if (cr > PPC_CR0) {
+ needComma = true;
+ SStream_concat(&ss, " cr%d", cr - PPC_CR0);
+ op_addReg(MI, PPC_REG_CR0 + cr - PPC_CR0);
+ }
+ }
+ }
+
+ if (MCOperand_isImm(MCInst_getOperand(MI, 2)) &&
+ MCOperand_getImm(MCInst_getOperand(MI, 2)) != 0) {
+ if (needComma)
+ SStream_concat0(&ss, ",");
+
+ SStream_concat0(&ss, " $\xFF\x03\x01");
+ }
+
+ tmp = cs_strdup(ss.buffer);
+ AsmMnem = tmp;
+ for(AsmOps = tmp; *AsmOps; AsmOps++) {
+ if (*AsmOps == ' ' || *AsmOps == '\t') {
+ *AsmOps = '\0';
+ AsmOps++;
+ break;
+ }
+ }
+
+ SStream_concat0(OS, AsmMnem);
+ if (*AsmOps) {
+ SStream_concat0(OS, "\t");
+ for (c = AsmOps; *c; c++) {
+ if (*c == '$') {
+ c += 1;
+ if (*c == (char)0xff) {
+ c += 1;
+ OpIdx = *c - 1;
+ c += 1;
+ PrintMethodIdx = *c - 1;
+ printCustomAliasOperand(MI, OpIdx, PrintMethodIdx, OS);
+ } else
+ printOperand(MI, *c - 1, OS);
+ } else {
+ SStream_concat1(OS, *c);
+ }
+ }
+ }
+
+ return tmp;
+}
+
+static bool isBOCTRBranch(unsigned int op)
+{
+ return ((op >= PPC_BDNZ) && (op <= PPC_BDZp));
+}
+
+void PPC_printInst(MCInst *MI, SStream *O, void *Info)
+{
+ char *mnem;
+ unsigned int opcode = MCInst_getOpcode(MI);
+
+ // printf("opcode = %u\n", opcode);
+
+ // Check for slwi/srwi mnemonics.
+ if (opcode == PPC_RLWINM) {
+ unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2));
+ unsigned char MB = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3));
+ unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 4));
+ bool useSubstituteMnemonic = false;
+
+ if (SH <= 31 && MB == 0 && ME == (31 - SH)) {
+ SStream_concat0(O, "slwi\t");
+ MCInst_setOpcodePub(MI, PPC_INS_SLWI);
+ useSubstituteMnemonic = true;
+ }
+
+ if (SH <= 31 && MB == (32 - SH) && ME == 31) {
+ SStream_concat0(O, "srwi\t");
+ MCInst_setOpcodePub(MI, PPC_INS_SRWI);
+ useSubstituteMnemonic = true;
+ SH = 32 - SH;
+ }
+
+ if (useSubstituteMnemonic) {
+ printOperand(MI, 0, O);
+ SStream_concat0(O, ", ");
+ printOperand(MI, 1, O);
+
+ if (SH > HEX_THRESHOLD)
+ SStream_concat(O, ", 0x%x", (unsigned int)SH);
+ else
+ SStream_concat(O, ", %u", (unsigned int)SH);
+
+ if (MI->csh->detail) {
+ cs_ppc *ppc = &MI->flat_insn->detail->ppc;
+
+ ppc->operands[ppc->op_count].type = PPC_OP_IMM;
+ ppc->operands[ppc->op_count].imm = SH;
+ ++ppc->op_count;
+ }
+
+ return;
+ }
+ }
+
+ if ((opcode == PPC_OR || opcode == PPC_OR8) &&
+ MCOperand_getReg(MCInst_getOperand(MI, 1)) == MCOperand_getReg(MCInst_getOperand(MI, 2))) {
+ SStream_concat0(O, "mr\t");
+ MCInst_setOpcodePub(MI, PPC_INS_MR);
+
+ printOperand(MI, 0, O);
+ SStream_concat0(O, ", ");
+ printOperand(MI, 1, O);
+
+ return;
+ }
+
+ if (opcode == PPC_RLDICR ||
+ opcode == PPC_RLDICR_32) {
+ unsigned char SH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 2));
+ unsigned char ME = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 3));
+
+ // rldicr RA, RS, SH, 63-SH == sldi RA, RS, SH
+ if (63 - SH == ME) {
+ SStream_concat0(O, "sldi\t");
+ MCInst_setOpcodePub(MI, PPC_INS_SLDI);
+
+ printOperand(MI, 0, O);
+ SStream_concat0(O, ", ");
+ printOperand(MI, 1, O);
+
+ if (SH > HEX_THRESHOLD)
+ SStream_concat(O, ", 0x%x", (unsigned int)SH);
+ else
+ SStream_concat(O, ", %u", (unsigned int)SH);
+
+ if (MI->csh->detail) {
+ cs_ppc *ppc = &MI->flat_insn->detail->ppc;
+
+ ppc->operands[ppc->op_count].type = PPC_OP_IMM;
+ ppc->operands[ppc->op_count].imm = SH;
+ ++ppc->op_count;
+ }
+
+
+ return;
+ }
+ }
+
+ // dcbt[st] is printed manually here because:
+ // 1. The assembly syntax is different between embedded and server targets
+ // 2. We must print the short mnemonics for TH == 0 because the
+ // embedded/server syntax default will not be stable across assemblers
+ // The syntax for dcbt is:
+ // dcbt ra, rb, th [server]
+ // dcbt th, ra, rb [embedded]
+ // where th can be omitted when it is 0. dcbtst is the same.
+ if (opcode == PPC_DCBT || opcode == PPC_DCBTST) {
+ unsigned char TH = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 0));
+
+ SStream_concat0(O, "dcbt");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBT);
+
+ if (opcode == PPC_DCBTST) {
+ SStream_concat0(O, "st");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBTST);
+ }
+
+ if (TH == 16) {
+ SStream_concat0(O, "t");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBTSTT);
+ }
+
+ SStream_concat0(O, "\t");
+
+ if (MI->csh->mode & CS_MODE_BOOKE && TH != 0 && TH != 16) {
+ if (TH > HEX_THRESHOLD)
+ SStream_concat(O, "0x%x, ", (unsigned int)TH);
+ else
+ SStream_concat(O, "%u, ", (unsigned int)TH);
+
+ if (MI->csh->detail) {
+ cs_ppc *ppc = &MI->flat_insn->detail->ppc;
+
+ ppc->operands[ppc->op_count].type = PPC_OP_IMM;
+ ppc->operands[ppc->op_count].imm = TH;
+ ++ppc->op_count;
+ }
+ }
+
+ printOperand(MI, 1, O);
+ SStream_concat0(O, ", ");
+ printOperand(MI, 2, O);
+
+ if (!(MI->csh->mode & CS_MODE_BOOKE) && TH != 0 && TH != 16) {
+ if (TH > HEX_THRESHOLD)
+ SStream_concat(O, ", 0x%x", (unsigned int)TH);
+ else
+ SStream_concat(O, ", %u", (unsigned int)TH);
+
+ if (MI->csh->detail) {
+ cs_ppc *ppc = &MI->flat_insn->detail->ppc;
+
+ ppc->operands[ppc->op_count].type = PPC_OP_IMM;
+ ppc->operands[ppc->op_count].imm = TH;
+ ++ppc->op_count;
+ }
+ }
+
+ return;
+ }
+
+ if (opcode == PPC_DCBF) {
+ unsigned char L = (unsigned char)MCOperand_getImm(MCInst_getOperand(MI, 0));
+
+ if (!L || L == 1 || L == 3) {
+ SStream_concat0(O, "dcbf");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBF);
+
+ if (L == 1 || L == 3) {
+ SStream_concat0(O, "l");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBFL);
+ }
+
+ if (L == 3) {
+ SStream_concat0(O, "p");
+ MCInst_setOpcodePub(MI, PPC_INS_DCBFLP);
+ }
+
+ SStream_concat0(O, "\t");
+
+ printOperand(MI, 1, O);
+ SStream_concat0(O, ", ");
+ printOperand(MI, 2, O);
+
+ return;
+ }
+ }
+
+ if (opcode == PPC_B || opcode == PPC_BA || opcode == PPC_BL ||
+ opcode == PPC_BLA) {
+ int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
+ bd = SignExtend64(bd, 24);
+ MCOperand_setImm(MCInst_getOperand(MI, 0), bd);
+ }
+
+ if (opcode == PPC_gBC || opcode == PPC_gBCA || opcode == PPC_gBCL ||
+ opcode == PPC_gBCLA) {
+ int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2));
+ bd = SignExtend64(bd, 14);
+ MCOperand_setImm(MCInst_getOperand(MI, 2), bd);
+ }
+
+ if (isBOCTRBranch(MCInst_getOpcode(MI))) {
+ if (MCOperand_isImm(MCInst_getOperand(MI,0))) {
+ int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 0));
+ bd = SignExtend64(bd, 14);
+ MCOperand_setImm(MCInst_getOperand(MI, 0), bd);
+ }
+ }
+
+ mnem = printAliasBcc(MI, O, Info);
+ if (!mnem)
+ mnem = printAliasInstr(MI, O, Info);
+
+ if (mnem != NULL) {
+ if (strlen(mnem) > 0) {
+ // check to remove the last letter of ('.', '-', '+')
+ if (mnem[strlen(mnem) - 1] == '-' || mnem[strlen(mnem) - 1] == '+' || mnem[strlen(mnem) - 1] == '.')
+ mnem[strlen(mnem) - 1] = '\0';
+
+ MCInst_setOpcodePub(MI, PPC_map_insn(mnem));
+
+ if (MI->csh->detail) {
+ struct ppc_alias alias;
+
+ if (PPC_alias_insn(mnem, &alias)) {
+ MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc;
+ }
+ }
+ }
+
+ cs_mem_free(mnem);
+ } else
+ printInstruction(MI, O);
+}
+
+// FIXME
+enum ppc_bc_hint {
+ PPC_BC_LT_MINUS = (0 << 5) | 14,
+ PPC_BC_LE_MINUS = (1 << 5) | 6,
+ PPC_BC_EQ_MINUS = (2 << 5) | 14,
+ PPC_BC_GE_MINUS = (0 << 5) | 6,
+ PPC_BC_GT_MINUS = (1 << 5) | 14,
+ PPC_BC_NE_MINUS = (2 << 5) | 6,
+ PPC_BC_UN_MINUS = (3 << 5) | 14,
+ PPC_BC_NU_MINUS = (3 << 5) | 6,
+ PPC_BC_LT_PLUS = (0 << 5) | 15,
+ PPC_BC_LE_PLUS = (1 << 5) | 7,
+ PPC_BC_EQ_PLUS = (2 << 5) | 15,
+ PPC_BC_GE_PLUS = (0 << 5) | 7,
+ PPC_BC_GT_PLUS = (1 << 5) | 15,
+ PPC_BC_NE_PLUS = (2 << 5) | 7,
+ PPC_BC_UN_PLUS = (3 << 5) | 15,
+ PPC_BC_NU_PLUS = (3 << 5) | 7,
+};
+
+// FIXME
+// normalize CC to remove _MINUS & _PLUS
+static int cc_normalize(int cc)
+{
+ switch(cc) {
+ default: return cc;
+ case PPC_BC_LT_MINUS: return PPC_BC_LT;
+ case PPC_BC_LE_MINUS: return PPC_BC_LE;
+ case PPC_BC_EQ_MINUS: return PPC_BC_EQ;
+ case PPC_BC_GE_MINUS: return PPC_BC_GE;
+ case PPC_BC_GT_MINUS: return PPC_BC_GT;
+ case PPC_BC_NE_MINUS: return PPC_BC_NE;
+ case PPC_BC_UN_MINUS: return PPC_BC_UN;
+ case PPC_BC_NU_MINUS: return PPC_BC_NU;
+ case PPC_BC_LT_PLUS : return PPC_BC_LT;
+ case PPC_BC_LE_PLUS : return PPC_BC_LE;
+ case PPC_BC_EQ_PLUS : return PPC_BC_EQ;
+ case PPC_BC_GE_PLUS : return PPC_BC_GE;
+ case PPC_BC_GT_PLUS : return PPC_BC_GT;
+ case PPC_BC_NE_PLUS : return PPC_BC_NE;
+ case PPC_BC_UN_PLUS : return PPC_BC_UN;
+ case PPC_BC_NU_PLUS : return PPC_BC_NU;
+ }
+}
+
+static void printPredicateOperand(MCInst *MI, unsigned OpNo,
+ SStream *O, const char *Modifier)
+{
+ unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ MI->flat_insn->detail->ppc.bc = (ppc_bc)cc_normalize(Code);
+
+ if (!strcmp(Modifier, "cc")) {
+ switch ((ppc_predicate)Code) {
+ default: // unreachable
+ case PPC_PRED_LT_MINUS:
+ case PPC_PRED_LT_PLUS:
+ case PPC_PRED_LT:
+ SStream_concat0(O, "lt");
+ return;
+ case PPC_PRED_LE_MINUS:
+ case PPC_PRED_LE_PLUS:
+ case PPC_PRED_LE:
+ SStream_concat0(O, "le");
+ return;
+ case PPC_PRED_EQ_MINUS:
+ case PPC_PRED_EQ_PLUS:
+ case PPC_PRED_EQ:
+ SStream_concat0(O, "eq");
+ return;
+ case PPC_PRED_GE_MINUS:
+ case PPC_PRED_GE_PLUS:
+ case PPC_PRED_GE:
+ SStream_concat0(O, "ge");
+ return;
+ case PPC_PRED_GT_MINUS:
+ case PPC_PRED_GT_PLUS:
+ case PPC_PRED_GT:
+ SStream_concat0(O, "gt");
+ return;
+ case PPC_PRED_NE_MINUS:
+ case PPC_PRED_NE_PLUS:
+ case PPC_PRED_NE:
+ SStream_concat0(O, "ne");
+ return;
+ case PPC_PRED_UN_MINUS:
+ case PPC_PRED_UN_PLUS:
+ case PPC_PRED_UN:
+ SStream_concat0(O, "un");
+ return;
+ case PPC_PRED_NU_MINUS:
+ case PPC_PRED_NU_PLUS:
+ case PPC_PRED_NU:
+ SStream_concat0(O, "nu");
+ return;
+ case PPC_PRED_BIT_SET:
+ case PPC_PRED_BIT_UNSET:
+ // llvm_unreachable("Invalid use of bit predicate code");
+ SStream_concat0(O, "invalid-predicate");
+ return;
+ }
+ }
+
+ if (!strcmp(Modifier, "pm")) {
+ switch ((ppc_predicate)Code) {
+ case PPC_PRED_LT:
+ case PPC_PRED_LE:
+ case PPC_PRED_EQ:
+ case PPC_PRED_GE:
+ case PPC_PRED_GT:
+ case PPC_PRED_NE:
+ case PPC_PRED_UN:
+ case PPC_PRED_NU:
+ return;
+ case PPC_PRED_LT_MINUS:
+ case PPC_PRED_LE_MINUS:
+ case PPC_PRED_EQ_MINUS:
+ case PPC_PRED_GE_MINUS:
+ case PPC_PRED_GT_MINUS:
+ case PPC_PRED_NE_MINUS:
+ case PPC_PRED_UN_MINUS:
+ case PPC_PRED_NU_MINUS:
+ SStream_concat0(O, "-");
+ return;
+ case PPC_PRED_LT_PLUS:
+ case PPC_PRED_LE_PLUS:
+ case PPC_PRED_EQ_PLUS:
+ case PPC_PRED_GE_PLUS:
+ case PPC_PRED_GT_PLUS:
+ case PPC_PRED_NE_PLUS:
+ case PPC_PRED_UN_PLUS:
+ case PPC_PRED_NU_PLUS:
+ SStream_concat0(O, "+");
+ return;
+ case PPC_PRED_BIT_SET:
+ case PPC_PRED_BIT_UNSET:
+ // llvm_unreachable("Invalid use of bit predicate code");
+ SStream_concat0(O, "invalid-predicate");
+ return;
+ default: // unreachable
+ return;
+ }
+ // llvm_unreachable("Invalid predicate code");
+ }
+
+ //assert(StringRef(Modifier) == "reg" &&
+ // "Need to specify 'cc', 'pm' or 'reg' as predicate op modifier!");
+ printOperand(MI, OpNo + 1, O);
+}
+
+static void printATBitsAsHint(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned Code = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ if (Code == 2) {
+ SStream_concat0(O, "-");
+ } else if (Code == 3) {
+ SStream_concat0(O, "+");
+ }
+}
+
+static void printU1ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ // assert(Value <= 1 && "Invalid u1imm argument!");
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU2ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ //assert(Value <= 3 && "Invalid u2imm argument!");
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU3ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ //assert(Value <= 8 && "Invalid u3imm argument!");
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU4ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ //assert(Value <= 15 && "Invalid u4imm argument!");
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printS5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ int Value = (int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ Value = SignExtend32(Value, 5);
+
+ printInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU5ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ //assert(Value <= 31 && "Invalid u5imm argument!");
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU6ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ //assert(Value <= 63 && "Invalid u6imm argument!");
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU7ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ //assert(Value <= 127 && "Invalid u7imm argument!");
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+// Operands of BUILD_VECTOR are signed and we use this to print operands
+// of XXSPLTIB which are unsigned. So we simply truncate to 8 bits and
+// print as unsigned.
+static void printU8ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU10ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned int Value = (unsigned int)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ //assert(Value <= 1023 && "Invalid u10imm argument!");
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printU12ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned short Value = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+
+ // assert(Value <= 4095 && "Invalid u12imm argument!");
+
+ printUInt32(O, Value);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Value;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printS16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
+ short Imm = (short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ printInt32(O, Imm);
+
+ if (MI->csh->detail) {
+ if (MI->csh->doing_mem) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = Imm;
+ } else {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+ }
+ } else
+ printOperand(MI, OpNo, O);
+}
+
+static void printU16ImmOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ if (MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
+ unsigned short Imm = (unsigned short)MCOperand_getImm(MCInst_getOperand(MI, OpNo));
+ printUInt32(O, Imm);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = Imm;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+ } else
+ printOperand(MI, OpNo, O);
+}
+
+static void printBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
+ printOperand(MI, OpNo, O);
+
+ return;
+ }
+
+ // Branches can take an immediate operand. This is used by the branch
+ // selection pass to print .+8, an eight byte displacement from the PC.
+ // O << ".+";
+ printAbsBranchOperand(MI, OpNo, O);
+}
+
+static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ int64_t imm;
+
+ if (!MCOperand_isImm(MCInst_getOperand(MI, OpNo))) {
+ printOperand(MI, OpNo, O);
+
+ return;
+ }
+
+ imm = SignExtend32(MCOperand_getImm(MCInst_getOperand(MI, OpNo)) * 4, 32);
+ //imm = MCOperand_getImm(MCInst_getOperand(MI, OpNo)) * 4;
+
+ if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) {
+ imm += MI->address;
+ }
+
+ printUInt64(O, imm);
+
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ unsigned RegNo;
+ unsigned CCReg = MCOperand_getReg(MCInst_getOperand(MI, OpNo));
+
+ switch (CCReg) {
+ default: // llvm_unreachable("Unknown CR register");
+ case PPC_CR0: RegNo = 0; break;
+ case PPC_CR1: RegNo = 1; break;
+ case PPC_CR2: RegNo = 2; break;
+ case PPC_CR3: RegNo = 3; break;
+ case PPC_CR4: RegNo = 4; break;
+ case PPC_CR5: RegNo = 5; break;
+ case PPC_CR6: RegNo = 6; break;
+ case PPC_CR7: RegNo = 7; break;
+ }
+
+ printUInt32(O, 0x80 >> RegNo);
+}
+
+static void printMemRegImm(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ set_mem_access(MI, true);
+
+ printS16ImmOperand(MI, OpNo, O);
+
+ SStream_concat0(O, "(");
+
+ if (MCOperand_getReg(MCInst_getOperand(MI, OpNo + 1)) == PPC_R0)
+ SStream_concat0(O, "0");
+ else
+ printOperand(MI, OpNo + 1, O);
+
+ SStream_concat0(O, ")");
+
+ set_mem_access(MI, false);
+}
+
+static void printMemRegReg(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ // When used as the base register, r0 reads constant zero rather than
+ // the value contained in the register. For this reason, the darwin
+ // assembler requires that we print r0 as 0 (no r) when used as the base.
+ if (MCOperand_getReg(MCInst_getOperand(MI, OpNo)) == PPC_R0)
+ SStream_concat0(O, "0");
+ else
+ printOperand(MI, OpNo, O);
+ SStream_concat0(O, ", ");
+
+ printOperand(MI, OpNo + 1, O);
+}
+
+static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ set_mem_access(MI, true);
+ //printBranchOperand(MI, OpNo, O);
+
+ // On PPC64, VariantKind is VK_None, but on PPC32, it's VK_PLT, and it must
+ // come at the _end_ of the expression.
+
+ SStream_concat0(O, "(");
+ printOperand(MI, OpNo + 1, O);
+ SStream_concat0(O, ")");
+
+ set_mem_access(MI, false);
+}
+
+/// stripRegisterPrefix - This method strips the character prefix from a
+/// register name so that only the number is left. Used by for linux asm.
+static char *stripRegisterPrefix(const char *RegName)
+{
+ switch (RegName[0]) {
+ case 'r':
+ case 'f':
+ case 'q': // for QPX
+ case 'v':
+ if (RegName[1] == 's')
+ return cs_strdup(RegName + 2);
+
+ return cs_strdup(RegName + 1);
+ case 'c':
+ if (RegName[1] == 'r') {
+ // skip the first 2 letters "cr"
+ char *name = cs_strdup(RegName + 2);
+
+ // also strip the last 2 letters
+ name[strlen(name) - 2] = '\0';
+
+ return name;
+ }
+ }
+
+ return cs_strdup(RegName);
+}
+
+static void printOperand(MCInst *MI, unsigned OpNo, SStream *O)
+{
+ MCOperand *Op = MCInst_getOperand(MI, OpNo);
+ if (MCOperand_isReg(Op)) {
+ unsigned reg = MCOperand_getReg(Op);
+#ifndef CAPSTONE_DIET
+ const char *RegName = getRegisterName(reg);
+
+ // printf("reg = %u (%s)\n", reg, RegName);
+
+ // convert internal register ID to public register ID
+ reg = PPC_name_reg(RegName);
+
+ // The linux and AIX assembler does not take register prefixes.
+ if (MI->csh->syntax == CS_OPT_SYNTAX_NOREGNAME) {
+ char *name = stripRegisterPrefix(RegName);
+ SStream_concat0(O, name);
+ cs_mem_free(name);
+ } else
+ SStream_concat0(O, RegName);
+#endif
+
+ if (MI->csh->detail) {
+ if (MI->csh->doing_mem) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.base = reg;
+ } else {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_REG;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].reg = reg;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+ }
+
+ return;
+ }
+
+ if (MCOperand_isImm(Op)) {
+ int32_t imm = (int32_t)MCOperand_getImm(Op);
+ printInt32(O, imm);
+
+ if (MI->csh->detail) {
+ if (MI->csh->doing_mem) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].mem.disp = (int32_t)imm;
+ } else {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = imm;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+ }
+ }
+}
+
+static void op_addImm(MCInst *MI, int v)
+{
+ if (MI->csh->detail) {
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_IMM;
+ MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].imm = v;
+ MI->flat_insn->detail->ppc.op_count++;
+ }
+}
+
+#define PRINT_ALIAS_INSTR
+#include "PPCGenRegisterName.inc"
+#include "PPCGenAsmWriter.inc"
+
+#endif