#include #include #include #include "capstone/capstone.h" #include "decode/decode.h" bool crbit_equal(ppc_reg cs_reg, uint32_t crbit) { if (crbit >= 32) { printf("invalid new crbit %d\n", crbit); return false; } if (cs_reg < PPC_REG_CR0EQ || cs_reg > PPC_REG_CR7UN) { printf("invalid cs crbit cs reg %d\n", cs_reg); return false; } uint32_t crn = 0; uint32_t bit = 0; if (PPC_REG_CR0EQ <= cs_reg && cs_reg <= PPC_REG_CR7EQ) { crn = cs_reg - PPC_REG_CR0EQ; bit = 2; } else if (PPC_REG_CR0GT <= cs_reg && cs_reg <= PPC_REG_CR7GT) { crn = cs_reg - PPC_REG_CR0GT; bit = 1; } else if (PPC_REG_CR0LT <= cs_reg && cs_reg <= PPC_REG_CR7LT) { crn = cs_reg - PPC_REG_CR0LT; bit = 0; } else { // PPC_REG_CR0UN <= cs_reg && cs_reg <= PPC_REG_CR7UN crn = cs_reg - PPC_REG_CR0UN; bit = 3; } uint32_t cs_equivalent = 4*crn + bit; return crbit == cs_equivalent; } bool ops_equal(csh handle, const cs_ppc_op* capstone_op, const Operand* new_op) { switch (new_op->cls) { case PPC_OP_NONE: return capstone_op->type == PPC_OP_INVALID; case PPC_OP_UIMM: { // handle RA|0 if (capstone_op->type == PPC_OP_REG) { if (capstone_op->reg == PPC_REG_INVALID) { if (new_op->uimm != 0) { printf("new operand is UIMM %ld != 0, when capstone is PPC_REG_INVALID\n", new_op->uimm); return false; } return true; } printf("new operand is UIMM %ld, capstone is REG %d != PPC_REG_INVALID\n", new_op->uimm, capstone_op->reg); return false; } if (capstone_op->type != PPC_OP_IMM) { printf("new operand is UIMM, but capstone is %d\n", capstone_op->type); return false; } int64_t capstone_imm = capstone_op->imm; int64_t new_imm = new_op->uimm; if (capstone_imm != new_imm) { printf("new operand UIMM is %#lx, capstone imm is %#lx\n", new_imm, capstone_imm); return false; } return true; } case PPC_OP_SIMM: { if (capstone_op->type != PPC_OP_IMM) { printf("new operand is SIMM, but capstone is %d\n", capstone_op->type); return false; } int64_t capstone_imm = capstone_op->imm; int64_t new_imm = new_op->simm; if (capstone_imm != new_imm) { printf("new operand SIMM is %#lx, capstone imm is %#lx\n", new_imm, capstone_imm); return false; } return true; } case PPC_OP_REG_RA: case PPC_OP_REG_RB: case PPC_OP_REG_RC: case PPC_OP_REG_RD: case PPC_OP_REG_RS: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is register, but capstone is %d\n", capstone_op->type); return false; } int capstone_reg = capstone_op->reg - PPC_REG_R0; int new_reg = new_op->reg - NUPPC_REG_GPR0; if (capstone_reg != new_reg) { printf("new operand register %d, capstone register %d\n", new_reg, capstone_reg); return false; } return true; } case PPC_OP_REG_FRA: case PPC_OP_REG_FRB: case PPC_OP_REG_FRC: case PPC_OP_REG_FRD: case PPC_OP_REG_FRS: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is register, but capstone is %d\n", capstone_op->type); return false; } int capstone_reg = capstone_op->reg - PPC_REG_F0; int new_reg = new_op->reg - NUPPC_REG_FR0; if (capstone_reg != new_reg) { printf("new operand register %d, capstone register %d\n", new_reg, capstone_reg); return false; } return true; } case PPC_OP_REG_CRFD: case PPC_OP_REG_CRFD_IMPLY0: case PPC_OP_REG_CRFS: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is CR, but capstone is %d\n", capstone_op->type); return false; } int capstone_reg = capstone_op->reg - PPC_REG_CR0; int new_reg = new_op->reg - NUPPC_REG_CRF0; if (capstone_reg != new_reg) { printf("new operand CR %d, capstone CR register %d\n", new_reg, capstone_reg); return false; } return true; } case PPC_OP_CRBIT_A: case PPC_OP_CRBIT_B: case PPC_OP_CRBIT_D: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is CRbit, but capstone is %d\n", capstone_op->type); return false; } const char* capstone_name = cs_reg_name(handle, capstone_op->reg); if (!crbit_equal(capstone_op->reg, new_op->crbit)) { printf("new operand CR %d, capstone CR register %d (%s)\n", new_op->crbit, capstone_op->reg, capstone_name); return false; } return true; } case PPC_OP_REG_AV_VA: case PPC_OP_REG_AV_VB: case PPC_OP_REG_AV_VC: case PPC_OP_REG_AV_VD: case PPC_OP_REG_AV_VS: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is altivec register, but capstone is %d\n", capstone_op->type); return false; } int capstone_reg = capstone_op->reg - PPC_REG_V0; int new_reg = new_op->reg - NUPPC_REG_AV_VR0; if (capstone_reg != new_reg) { printf("new operand altivec register %d, capstone altivec register %d\n", new_reg, capstone_reg); return false; } return true; } case PPC_OP_REG_VSX_RA: case PPC_OP_REG_VSX_RB: case PPC_OP_REG_VSX_RC: case PPC_OP_REG_VSX_RD: case PPC_OP_REG_VSX_RS: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is vsx (full) register, but capstone is %d\n", capstone_op->type); return false; } const char* capstone_name = cs_reg_name(handle, capstone_op->reg); int new_reg = new_op->reg - NUPPC_REG_VSX_VR0; int capstone_reg; if (PPC_REG_VS0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_VS63) capstone_reg = capstone_op->reg - PPC_REG_VS0; else if (PPC_REG_V0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_V31) capstone_reg = capstone_op->reg - PPC_REG_V0 + 32; else { printf("new operand vsx (full) register %d, capstone register %d (%s) isn't any kind of vector\n", new_reg, capstone_op->reg, capstone_name); return false; } if (capstone_reg != new_reg) { printf("new operand vsx (full) register %d, capstone vsx register %d (%s)\n", new_reg, capstone_reg, capstone_name); return false; } return true; } case PPC_OP_REG_VSX_RA_DWORD0: case PPC_OP_REG_VSX_RB_DWORD0: case PPC_OP_REG_VSX_RC_DWORD0: case PPC_OP_REG_VSX_RD_DWORD0: case PPC_OP_REG_VSX_RS_DWORD0: { if (capstone_op->type != PPC_OP_REG) { printf("new operand is vsx (dword0) register, but capstone is %d\n", capstone_op->type); return false; } const char* capstone_name = cs_reg_name(handle, capstone_op->reg); int new_reg = new_op->reg - NUPPC_REG_VSX_VR0; int capstone_reg; if (PPC_REG_VS0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_VS63) capstone_reg = capstone_op->reg - PPC_REG_VS0; else if (PPC_REG_V0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_V31) capstone_reg = capstone_op->reg - PPC_REG_V0 + 32; else if (PPC_REG_F0 <= capstone_op->reg && capstone_op->reg <= PPC_REG_F31) capstone_reg = capstone_op->reg - PPC_REG_F0; else { printf("new operand vsx (dword0) register %d, capstone register %d (%s) isn't any kind of vector\n", new_reg, capstone_op->reg, capstone_name); return false; } if (capstone_reg != new_reg) { printf("new operand vsx (dword0) register %d, capstone vsx register %d (%s)\n", new_reg, capstone_reg, capstone_name); return false; } return true; } case PPC_OP_MEM_RA: { if (capstone_op->type != PPC_OP_MEM) { printf("new operand is memory, but capstone is %d\n", capstone_op->type); return false; } // memory are of the form RA|0 int new_reg = new_op->mem.reg - NUPPC_REG_GPR0; if (new_reg == 0) { if (capstone_op->mem.base != PPC_REG_INVALID) { printf("new operand mem reg is r0, capstone mem reg is %d != invalid\n", capstone_op->mem.base); return false; } } else { int capstone_reg = capstone_op->mem.base - PPC_REG_R0; if (capstone_reg != new_reg) { printf("new operand mem reg is %d, capstone mem reg is %d\n", new_reg, capstone_reg); return false; } } int capstone_offset = capstone_op->mem.disp; int new_offset = new_op->mem.offset; if (capstone_offset != new_offset) { printf("new operand mem offset is %d, capstone mem offset is %d\n", new_offset, capstone_offset); return false; } return true; } default: printf("unhandled class %d\n", new_op->cls); return false; } } uint32_t bc_to_bi(ppc_bc bc) { switch (bc) { case PPC_BC_LT: return 0; case PPC_BC_GT: return 1; case PPC_BC_EQ: return 2; case PPC_BC_SO: return 3; default: return 0xffffffff; } } uint32_t crx_to_bi(const ppc_op_crx* crx) { uint32_t crn = (crx->reg - PPC_REG_CR0); uint32_t extra = 0; switch (crx->cond) { case PPC_BC_LT: extra = 0; break; case PPC_BC_GT: extra = 1; break; case PPC_BC_EQ: extra = 2; break; case PPC_BC_SO: extra = 3; break; default: printf("bcx capstone op 0 cond is weird %d\n", crx->cond); return 0xffffffff; } return crx->scale*crn + extra; } // compare bcx