Skip to content
This repository has been archived by the owner on May 18, 2022. It is now read-only.

Commit

Permalink
PPC: Fix absolute/relative offset for branch instruction
Browse files Browse the repository at this point in the history
PPC: Fix non handling of bc instruction that uses the CTR
  • Loading branch information
kratolp committed Oct 1, 2014
1 parent 39eb84a commit a3f0aef
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 64 deletions.
179 changes: 115 additions & 64 deletions arch/PowerPC/PPCInstPrinter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -775,100 +771,155 @@ 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_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)) {
int cr = getBICRCond(MCOperand_getReg(MCInst_getOperand(MI, 1)));
switch(cr) {
case CREQ:
SStream_concat(&ss, opCode, "eq");
SStream_concat(&ss, opCode, "ne");
break;
case CRGT:
SStream_concat(&ss, opCode, "gt");
SStream_concat(&ss, opCode, "le");
break;
case CRLT:
SStream_concat(&ss, opCode, "lt");
SStream_concat(&ss, opCode, "ge");
break;
case CRUN:
SStream_concat(&ss, opCode, "so");
SStream_concat(&ss, opCode, "ns");
break;
}

if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
SStream_concat0(&ss, "-");
if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 15)
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)) <= 7) &&
(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, "ne");
SStream_concat(&ss, opCode, "eq");
break;
case CRGT:
SStream_concat(&ss, opCode, "le");
SStream_concat(&ss, opCode, "gt");
break;
case CRLT:
SStream_concat(&ss, opCode, "ge");
SStream_concat(&ss, opCode, "lt");
break;
case CRUN:
SStream_concat(&ss, opCode, "ns");
SStream_concat(&ss, opCode, "so");
break;
}

if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 6)
if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 14)
SStream_concat0(&ss, "-");
if(MCOperand_getImm(MCInst_getOperand(MI, 0)) == 7)
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);
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);
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;
default:
SStream_concat(&ss, " cr%d", cr-PPC_CR0);
} else {
needComma = 0;
break;
}
}
}

Expand Down
37 changes: 37 additions & 0 deletions arch/PowerPC/PPCMapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 3 additions & 0 deletions arch/PowerPC/PPCMapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

5 changes: 5 additions & 0 deletions suite/ppcbranch.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
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

Expand Down

0 comments on commit a3f0aef

Please sign in to comment.