diff --git a/arch/PowerPC/PPCInstPrinter.c b/arch/PowerPC/PPCInstPrinter.c index f7707de3..9a472d3b 100644 --- a/arch/PowerPC/PPCInstPrinter.c +++ b/arch/PowerPC/PPCInstPrinter.c @@ -37,6 +37,7 @@ 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); @@ -89,6 +90,300 @@ void PPC_post_printer(csh ud, cs_insn *insn, char *insn_asm, MCInst *mci) #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 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) { + needComma = true; + SStream_concat0(&ss, " "); + + if (cr > PPC_CR0) { + SStream_concat(&ss, "4*cr%d+", cr - PPC_CR0); + } + + cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1))); + switch(cr) { + case CREQ: + SStream_concat0(&ss, "eq"); + op_addBC(MI, PPC_BC_EQ); + break; + case CRGT: + SStream_concat0(&ss, "gt"); + op_addBC(MI, PPC_BC_GT); + break; + case CRLT: + SStream_concat0(&ss, "lt"); + op_addBC(MI, PPC_BC_LT); + break; + case CRUN: + SStream_concat0(&ss, "so"); + op_addBC(MI, PPC_BC_SO); + break; + } + +#if 0 + cr = getBICR(MCOperand_getReg(MCInst_getOperand(MI, 1))); + if (cr > PPC_CR0) { + if (MI->csh->detail) { + MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].type = PPC_OP_CRX; + MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.scale = 4; + MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.reg = PPC_REG_CR0 + cr - PPC_CR0; + MI->flat_insn->detail->ppc.operands[MI->flat_insn->detail->ppc.op_count].crx.cond = MI->flat_insn->detail->ppc.bc; + MI->flat_insn->detail->ppc.op_count++; + } + } +#endif + } 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; +} + void PPC_printInst(MCInst *MI, SStream *O, void *Info) { char *mnem; @@ -279,17 +574,23 @@ void PPC_printInst(MCInst *MI, SStream *O, void *Info) MCOperand_setImm(MCInst_getOperand(MI, 0), bd); } - mnem = printAliasInstr(MI, O, Info); + mnem = printAliasBcc(MI, O, Info); + if (!mnem) + mnem = printAliasInstr(MI, O, Info); + if (mnem != NULL) { if (strlen(mnem) > 0) { - struct ppc_alias alias; // 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) { - MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc; + struct ppc_alias alias; + + if (PPC_alias_insn(mnem, &alias)) { + MI->flat_insn->detail->ppc.bc = (ppc_bc)alias.cc; + } } } @@ -690,10 +991,6 @@ static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O) } } - -#define GET_REGINFO_ENUM -#include "PPCGenRegisterInfo.inc" - static void printcrbitm(MCInst *MI, unsigned OpNo, SStream *O) { unsigned RegNo; @@ -761,10 +1058,9 @@ static void printTLSCall(MCInst *MI, unsigned OpNo, SStream *O) set_mem_access(MI, false); } -#ifndef CAPSTONE_DIET /// stripRegisterPrefix - This method strips the character prefix from a /// register name so that only the number is left. Used by for linux asm. -static const char *stripRegisterPrefix(const char *RegName) +static char *stripRegisterPrefix(const char *RegName) { switch (RegName[0]) { case 'r': @@ -772,36 +1068,43 @@ static const char *stripRegisterPrefix(const char *RegName) case 'q': // for QPX case 'v': if (RegName[1] == 's') - return RegName + 2; - return RegName + 1; + return cs_strdup(RegName + 2); + + return cs_strdup(RegName + 1); case 'c': - if (RegName[1] == 'r') - return RegName + 2; + 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 RegName; + return cs_strdup(RegName); } -#endif 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); + 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) - RegName = stripRegisterPrefix(RegName); - - SStream_concat0(O, RegName); -#endif + 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); if (MI->csh->detail) { if (MI->csh->doing_mem) { diff --git a/arch/PowerPC/PPCMapping.c b/arch/PowerPC/PPCMapping.c index 67fa1850..37eb8565 100644 --- a/arch/PowerPC/PPCMapping.c +++ b/arch/PowerPC/PPCMapping.c @@ -417,7 +417,6 @@ const char *PPC_group_name(csh handle, unsigned int id) #endif } -#if 0 static const struct ppc_alias alias_insn_name_maps[] = { //{ PPC_INS_BTA, "bta" }, { PPC_INS_B, PPC_BC_LT, "blt" }, @@ -513,32 +512,20 @@ static const struct ppc_alias alias_insn_name_maps[] = { bool PPC_alias_insn(const char *name, struct ppc_alias *alias) { size_t i; -#ifndef CAPSTONE_DIET - int x; -#endif + + alias->cc = PPC_BC_INVALID; for(i = 0; i < ARR_SIZE(alias_insn_name_maps); i++) { if (!strcmp(name, alias_insn_name_maps[i].mnem)) { - alias->id = alias_insn_name_maps[i].id; + // alias->id = alias_insn_name_maps[i].id; alias->cc = alias_insn_name_maps[i].cc; return true; } } -#ifndef CAPSTONE_DIET - // not really an alias insn - x = name2id(&insn_name_maps[1], ARR_SIZE(insn_name_maps) - 1, name); - if (x != -1) { - alias->id = insn_name_maps[x].id; - alias->cc = PPC_BC_INVALID; - return true; - } -#endif - // not found return false; } -#endif // check if this insn is relative branch bool PPC_abs_branch(cs_struct *h, unsigned int id) diff --git a/arch/PowerPC/PPCMapping.h b/arch/PowerPC/PPCMapping.h index 80bdc58e..a0d43318 100644 --- a/arch/PowerPC/PPCMapping.h +++ b/arch/PowerPC/PPCMapping.h @@ -33,5 +33,8 @@ bool PPC_abs_branch(cs_struct *h, unsigned int id); // map internal raw register to 'public' register ppc_reg PPC_map_register(unsigned int r); +// given alias mnemonic, return instruction ID & CC +bool PPC_alias_insn(const char *name, struct ppc_alias *alias); + #endif