ppc: alias for Bcc instructions. issue #1468

This commit is contained in:
Nguyen Anh Quynh 2019-05-10 00:57:03 +08:00
parent faa962426f
commit 30627ba853
3 changed files with 331 additions and 38 deletions

View File

@ -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) {

View File

@ -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)

View File

@ -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