PPC: Fix absolute/relative offset for branch instruction

PPC: Fix non handling of bc instruction that uses the CTR
This commit is contained in:
kratolp 2014-10-01 11:39:15 +02:00
parent 39eb84a9b1
commit a3f0aef79a
4 changed files with 169 additions and 73 deletions

View File

@ -145,7 +145,8 @@ void PPC_printInst(MCInst *MI, SStream *O, void *Info)
}
}
if (MCInst_getOpcode(MI) == PPC_gBC) {
if ((MCInst_getOpcode(MI) == PPC_gBC)||(MCInst_getOpcode(MI) == PPC_gBCA)||
(MCInst_getOpcode(MI) == PPC_gBCL)||(MCInst_getOpcode(MI) == PPC_gBCLA)) {
int64_t bd = MCOperand_getImm(MCInst_getOperand(MI, 2));
bd = SignExtend64(bd, 14);
MCOperand_setImm(MCInst_getOperand(MI, 2),bd);
@ -526,18 +527,13 @@ static void printAbsBranchOperand(MCInst *MI, unsigned OpNo, SStream *O)
}
imm = ((int)MCOperand_getImm(MCInst_getOperand(MI, OpNo)) << 2);
if (imm >= 0) {
if (imm > HEX_THRESHOLD)
SStream_concat(O, ".+0x%x", imm);
else
SStream_concat(O, ".+%u", imm);
} else {
if (imm < -HEX_THRESHOLD)
SStream_concat(O, ".-0x%x", -imm);
else
SStream_concat(O, ".-%u", -imm);
if (!PPC_abs_branch(MI->csh, MCInst_getOpcode(MI))) {
imm = (int)MI->address + imm;
}
SStream_concat(O, ".0x%x", 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;
@ -740,7 +736,7 @@ static char *printAliasInstrEx(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;
int needComma;
int decCtr, needComma;
char *tmp, *AsmMnem, *AsmOps, *c;
int OpIdx, PrintMethodIdx;
MCRegisterInfo *MRI = (MCRegisterInfo *)info;
@ -775,33 +771,23 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info)
if (MCInst_getNumOperands(MI) == 3 &&
MCOperand_isImm(MCInst_getOperand(MI, 0)) &&
(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 12) &&
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, "+");
(MCOperand_getImm(MCInst_getOperand(MI, 0)) >= 0) &&
(MCOperand_getImm(MCInst_getOperand(MI, 0)) <= 1)) {
SStream_concat(&ss, opCode, "dnzf");
decCtr = 1;
}
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 = 1;
}
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)) {
@ -825,50 +811,115 @@ static char *printAliasInstrEx(MCInst *MI, SStream *OS, void *info)
SStream_concat0(&ss, "-");
if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
SStream_concat0(&ss, "+");
decCtr = 0;
}
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 = 1;
}
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 = 1;
}
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 = 0;
}
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 = 0;
}
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 = 0;
}
if (MCOperand_isReg(MCInst_getOperand(MI, 1)) &&
GETREGCLASS_CONTAIN(PPC_CRBITRCRegClassID, 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)));
switch(cr) {
case PPC_CR1:
SStream_concat0(&ss, " cr1");
op_addReg(MI, PPC_REG_CR1);
if(decCtr) {
needComma = 1;
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");
break;
case CRGT:
SStream_concat0(&ss, "gt");
break;
case CRLT:
SStream_concat0(&ss, "lt");
break;
case CRUN:
SStream_concat0(&ss, "so");
break;
}
} else {
if(cr > PPC_CR0) {
needComma = 1;
break;
case PPC_CR2:
SStream_concat0(&ss, " cr2");
op_addReg(MI, PPC_REG_CR2);
needComma = 1;
break;
case PPC_CR3:
SStream_concat0(&ss, " cr3");
op_addReg(MI, PPC_REG_CR3);
needComma = 1;
break;
case PPC_CR4:
SStream_concat0(&ss, " cr4");
op_addReg(MI, PPC_REG_CR4);
needComma = 1;
break;
case PPC_CR5:
SStream_concat0(&ss, " cr5");
op_addReg(MI, PPC_REG_CR5);
needComma = 1;
break;
case PPC_CR6:
SStream_concat0(&ss, " cr6");
op_addReg(MI, PPC_REG_CR6);
needComma = 1;
break;
case PPC_CR7:
SStream_concat0(&ss, " cr7");
op_addReg(MI, PPC_REG_CR7);
needComma = 1;
break;
default:
SStream_concat(&ss, " cr%d", cr-PPC_CR0);
} else {
needComma = 0;
break;
}
}
}

View File

@ -8104,4 +8104,41 @@ bool PPC_alias_insn(const char *name, struct ppc_alias *alias)
return false;
}
// list all relative branch instructions
static unsigned int insn_abs[] = {
PPC_BA,
PPC_BCCA,
PPC_BCCLA,
PPC_BDNZA,
PPC_BDNZAm,
PPC_BDNZAp,
PPC_BDNZLA,
PPC_BDNZLAm,
PPC_BDNZLAp,
PPC_BDZA,
PPC_BDZAm,
PPC_BDZAp,
PPC_BDZLAm,
PPC_BDZLAp,
PPC_BLA,
PPC_gBCA,
PPC_gBCLA,
0
};
// check if this insn is relative branch
bool PPC_abs_branch(cs_struct *h, unsigned int id)
{
int i;
for (i = 0; insn_abs[i]; i++) {
if (id == insn_abs[i]) {
return true;
}
}
// not found
return false;
}
#endif

View File

@ -27,5 +27,8 @@ struct ppc_alias {
// given alias mnemonic, return instruction ID & CC
bool PPC_alias_insn(const char *name, struct ppc_alias *alias);
// check if this insn is relative branch
bool PPC_abs_branch(cs_struct *h, unsigned int id);
#endif

View File

@ -19,6 +19,11 @@ CODE32 += b"\x40\x9f\x10\x30" # bns cr5,.+0x94
CODE32 += b"\x42\x00\xff\xd8" # bdnz .-0x28
CODE32 += b"\x4d\x82\x00\x20" # beqlr
CODE32 += b"\x4e\x80\x00\x20" # blr
CODE32 += b"\x4a\x00\x00\x02" # ba .0xfe000000
CODE32 += b"\x41\x80\xff\xda" # blta .0xffffffd8
CODE32 += b"\x41\x4f\xff\x17" # bdztla 4*cr3+so, .0xffffff14
CODE32 += b"\x43\x20\x0c\x07" # bdnzla+ .0xc04
CODE32 += b"\x4c\x00\x04\x20" # bdnzfctr lt
_python3 = sys.version_info.major == 3