diff options
| author | Galen Williamson <galen@vector35.com> | 2025-06-29 11:23:58 -0400 |
|---|---|---|
| committer | Galen Williamson <galen@vector35.com> | 2025-06-29 18:28:48 -0400 |
| commit | e8206bc27e1633c7e4c99907f43bf67d2f200cd5 (patch) | |
| tree | 2315bec284e9bb692a0eb8986578fe18e2289d23 /arch/powerpc/capstone_compare_test.c | |
| parent | 91f1eccb6c41a7ef60fd66387ffae075f88141a4 (diff) | |
[powerpc] Full merge of PowerPC disassembler PRs, including:
* Remove dependency on capstone for PowerPC disassembly #6292
* Add support for PowerPC VLE instruction set #6740
* Add support for paired-single instructions #6821
* Various post-merge fixes and tweaks to disassembly and lifting
* Removal of dependence on capstone for assembler's scoring mechanism (capstone currently disabled, but not removed from codebase yet)
Diffstat (limited to 'arch/powerpc/capstone_compare_test.c')
| -rw-r--r-- | arch/powerpc/capstone_compare_test.c | 1875 |
1 files changed, 1875 insertions, 0 deletions
diff --git a/arch/powerpc/capstone_compare_test.c b/arch/powerpc/capstone_compare_test.c new file mode 100644 index 00000000..0c64c0eb --- /dev/null +++ b/arch/powerpc/capstone_compare_test.c @@ -0,0 +1,1875 @@ +#include <inttypes.h> +#include <stdio.h> +#include <string.h> + +#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 <bit> <label> (for decrementing CTR and checking if bit is true) +bool bcx_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address) +{ + if (bcx->operands[0].cls != PPC_OP_UIMM || bcx->operands[1].cls != PPC_OP_LABEL) + { + printf("bcx new ops 0/1 are %d/%d not UIMM/LABEL\n", + bcx->operands[0].cls, + bcx->operands[1].cls); + return false; + } + + if (capstone_instruction->op_count == 0) + { + // I don't know if it's idiomatic to be able to exclude the + // address for branch instructions, but when BD is 0 (whether + // the 'aa' bit is set or not), capstone omits the address + // token? + if (new_instruction->flags.aa && bcx->operands[1].label == 0) + return true; + + if (!new_instruction->flags.aa && bcx->operands[1].label == address) + return true; + + printf("bcx capstone 0 operands but new target %" PRIx64 " isn't address %" PRIx64" \n", + bcx->operands[1].label, address); + + return false; + } + + switch (capstone_instruction->operands[0].type) + { + case PPC_OP_IMM: + { + if (bcx->operands[1].label != capstone_instruction->operands[0].imm) + { + printf("bcx new op1 %08lx != capstone bc %08lx\n", + bcx->operands[1].uimm, capstone_instruction->operands[0].imm); + + return false; + } + + return true; + } + case PPC_OP_CRX: + { + printf("capstone op 0 is crx"); + return false; + } + + case PPC_OP_REG: + { + if (capstone_instruction->op_count >= 3) { + printf("bcx (crbit) capstone has too many (%d) args\n", + capstone_instruction->op_count); + + return false; + } + + if (!crbit_equal(capstone_instruction->operands[0].reg, bcx->operands[0].uimm)) + { + printf("bcx (crbit) crbit not equivalent: new uimm %ld, cs reg %d\n", + bcx->operands[0].uimm, capstone_instruction->operands[0].reg); + return false; + } + + if (capstone_instruction->op_count == 2 && (capstone_instruction->operands[1].imm != bcx->operands[1].label)) + { + printf("bcx (crbit) labels not equivalent: new label %lx, cs imm %lx\n", + bcx->operands[1].label, capstone_instruction->operands[1].imm); + + return false; + } + + return true; + } + + default: + printf("bcx capstone op 0 is %d not PPC_OP_IMM\n", + capstone_instruction->operands[0].type); + return false; + } + + return true; +} + +bool bcx_2op_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address) +{ + if (bcx->numOperands != 2) + { + printf("bcx 2op equal unknown number of arguments for new %ld\n", + bcx->numOperands); + + return false; + } + + if (bcx->operands[0].cls != PPC_OP_REG_CRFS && bcx->operands[1].cls != PPC_OP_LABEL) + { + printf("bcx 2op equal unexpected op classes %d/%d (new)\n", + bcx->operands[0].cls, bcx->operands[1].cls); + + return false; + } + + if (capstone_instruction->op_count == 0) + { + if (bcx->operands[0].reg != NUPPC_REG_CRF0) + { + printf("bcx 2op equal capstone 0 operands but new reg %d isn't CRF0 %d\n", + bcx->operands[0].reg, NUPPC_REG_CRF0); + + return false; + } + + // I don't know if it's idiomatic to be able to exclude the + // address for branch instructions, but when BD is 0 (whether + // the 'aa' bit is set or not), capstone omits the address + // token? + if (new_instruction->flags.aa && bcx->operands[1].label == 0) + return true; + + if (!new_instruction->flags.aa && bcx->operands[1].label == address) + return true; + + printf("bcx 2op equal capstone 0 operand but new target %lx isn't address %lx\n", + bcx->operands[1].label, address); + + return false; + } + + if (capstone_instruction->op_count == 1) + { + if (capstone_instruction->operands[0].type == PPC_OP_REG) + { + // I don't know if it's idiomatic to be able to exclude the + // address for branch instructions, but when BD is 0 (whether + // the 'aa' bit is set or not), capstone omits the address + // token? + if (new_instruction->flags.aa && bcx->operands[1].label == 0) + return true; + + if (!new_instruction->flags.aa && bcx->operands[1].label == address) + return true; + + printf("bcx 2op equal capstone 1 operand but new target %lx isn't address %lx\n", + bcx->operands[1].label, address); + + return false; + } + else if (capstone_instruction->operands[0].type == PPC_OP_IMM) + { + if (bcx->operands[0].reg != NUPPC_REG_CRF0) + { + printf("bcx 2op equal capstone 1 operand but new reg %d isn't CRF0 %d\n", + bcx->operands[0].reg, NUPPC_REG_CRF0); + + return false; + } + + if (bcx->operands[1].label != capstone_instruction->operands[0].imm) + { + printf("bcx 2op equal capstone 1 operand but new target %lx isn't capstone target %lx\n", + bcx->operands[1].label, capstone_instruction->operands[0].imm); + + return false; + } + + return true; + } + + printf("bcx 2op equal unexpected op type %d (capstone)\n", + capstone_instruction->operands[0].type); + + return false; + } + + if (capstone_instruction->operands[0].type != PPC_OP_REG || capstone_instruction->operands[1].type != PPC_OP_IMM) + { + printf("bcx 2op equal unexpected op type %d/%d (capstone)\n", + capstone_instruction->operands[0].type, capstone_instruction->operands[1].type); + + return false; + } + + uint32_t new_crn = bcx->operands[0].reg - NUPPC_REG_CRF0; + uint32_t cs_crn = capstone_instruction->operands[0].reg - PPC_REG_CR0; + + if (new_crn != cs_crn) + { + printf("bcx 2op equal regs are different cs %d != new %d\n", + cs_crn, new_crn); + + return false; + } + + if (capstone_instruction->operands[1].imm != bcx->operands[1].label) + { + printf("bcx 2op equal targets are different cs %#lx != new %#lx\n", + capstone_instruction->operands[1].imm, new_instruction->operands[1].label); + + return false; + } + + return true; +} + +bool bcx_1op_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcx, uint64_t address) +{ + if (bcx->numOperands != 1) + { + printf("bcx 1op equal unknown number of arguments for new %ld\n", + bcx->numOperands); + + return false; + } + + if (bcx->operands[0].cls != PPC_OP_LABEL) + { + printf("bcx 1op equal unexpected op class %d (new)\n", + bcx->operands[0].cls); + + return false; + } + + if (capstone_instruction->op_count == 0) + { + if (new_instruction->flags.aa && bcx->operands[0].label == 0) + return true; + + if (!new_instruction->flags.aa && bcx->operands[0].label == address) + return true; + + printf("bcx 1op equal address mismatch; capstone no operands, aa %d new label %lx address %lx\n", + new_instruction->flags.aa, bcx->operands[0].label, address); + + return false; + } + + if (capstone_instruction->op_count != 1) + { + printf("bcx 1op equal unexpected count %d (capstone)\n", + capstone_instruction->op_count); + + return false; + } + + if (capstone_instruction->operands[0].imm != bcx->operands[0].label) + { + printf("bcx 1op equal labels not equal cs %lx != new %lx\n", + capstone_instruction->operands[0].imm, + bcx->operands[0].label); + + return false; + } + + return true; +} + +bool bcregx_noargs_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction) +{ + if (new_instruction->numOperands != 0) + { + printf("bcregx_noargs unknown number of arguments for new %ld\n", + new_instruction->numOperands); + + return false; + } + + if (capstone_instruction->op_count == 0) + return true; + + // <op> <unnecessary target> + if (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM) + return true; + + printf("bcregx_noargs unexpected capstone structure: op count %d/op0 type %d\n", + capstone_instruction->op_count, capstone_instruction->operands[0].type); + return false; +} + +// for BCCTRx and BCLRx variants when just "<op> BI" +bool bcregx_bi_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction) +{ + if (new_instruction->numOperands != 1) + { + printf("bcregx_bi unknown number of arguments for new %ld\n", + new_instruction->numOperands); + + return false; + } + + if (new_instruction->operands[0].cls != PPC_OP_UIMM) + { + printf("bcregx_bi unknown new op0 class %d\n", + new_instruction->operands[0].cls); + + return false; + } + + // capstone uses just condition codes when CRn = 0; condition codes + // aren't treated as operands, so this happens when op_count == 0 and + // when capstone (unnecessarily?) adds a branch target + if (capstone_instruction->op_count == 0 || (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM)) + { + uint32_t cs_bi = bc_to_bi(capstone_instruction->bc); + if (new_instruction->operands[0].uimm != cs_bi) + { + printf("bcregx_bi cs_bi %d != new bi %ld\n", + cs_bi, new_instruction->operands[0].uimm); + + return false; + } + + return true; + } + + if (capstone_instruction->operands[0].type != PPC_OP_CRX) + { + printf("bcregx_bi unknown capstone op0 type %d\n", + capstone_instruction->operands[0].type); + + return false; + } + + uint32_t cs_bi = crx_to_bi(&capstone_instruction->operands[0].crx); + if (cs_bi != new_instruction->operands[0].uimm) + { + printf("bcregx_bi capstone BI %d != new BI %ld\n", + cs_bi, new_instruction->operands[0].uimm); + + return false; + } + + return true; +} + +// bclrx/bcctrx +bool bcregx1_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx) +{ + if (bcregx->numOperands != 1) + { + printf("bcregx1_equal unexpected num operands %ld (new)\n", + bcregx->numOperands); + + return false; + } + + if (bcregx->operands[0].cls != PPC_OP_CRBIT) + { + printf("bcregx1_equal unexpected op0 type %d isn't %d (new)\n", + bcregx->operands[0].cls, PPC_OP_CRBIT); + + return false; + } + + if (capstone_instruction->op_count == 0) + { + uint32_t cs_bi = bc_to_bi(capstone_instruction->bc); + if (bcregx->operands[0].crbit != cs_bi) + { + printf("bcregx1_equal capstone 1op op0 imm unexpected value %#x (new) != %#x (cs)\n", + bcregx->operands[0].crbit, cs_bi); + + return false; + } + + return true; + } + + else if (capstone_instruction->op_count == 1) + { + if (capstone_instruction->operands[0].type == PPC_OP_REG) + { + if (!crbit_equal(capstone_instruction->operands[0].reg, bcregx->operands[0].crbit)) + { + printf("bcregx1_equal capstone 1op op0 reg %d != crbit %d\n", + capstone_instruction->operands[0].reg, bcregx->operands[0].crbit); + return false; + } + + return true; + } + + printf("bcregx1_equal capstone 1op op0 unexpected type %d", + capstone_instruction->operands[0].type); + + return false; + } + else if (capstone_instruction->op_count == 2) + { + // <op> <BI> [unnecessary target] + if (capstone_instruction->operands[0].type == PPC_OP_CRX) + { + printf("bcregx1_equal 2op crx\n"); + return false; + } + else if (capstone_instruction->operands[0].type == PPC_OP_REG) + { + if (!crbit_equal(capstone_instruction->operands[0].reg, bcregx->operands[0].crbit)) + { + printf("bcregx1_equal capstone 2op op0 reg %d != crbit %d\n", + capstone_instruction->operands[0].reg, bcregx->operands[0].crbit); + return false; + } + return true; + } + else + { + printf("bcregx1_equal capstone 2op op0 unexpected type %d != PPC_OP_CRX %d\n", + capstone_instruction->operands[0].type, PPC_OP_CRX); + + return false; + } + } + + printf("bcregx1_equal unknown number of capstone operands %d\n", + capstone_instruction->op_count); + + return false; +} + +bool bcregx2_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx) +{ + if (bcregx->numOperands != 1) + { + printf("bcregx2_equal unexpected num operands %ld (new)\n", + bcregx->numOperands); + + return false; + } + + if (bcregx->operands[0].cls != PPC_OP_REG_CRFS_IMPLY0) + { + printf("bcregx2_equal unexpected op0 type %d isn't %d (new)\n", + bcregx->operands[0].cls, PPC_OP_REG_CRFS); + + return false; + } + + if (capstone_instruction->op_count == 0) + { + if (bcregx->operands[0].reg != NUPPC_REG_CRF0) + { + printf("bcregx2_equal capstone no ops but crn is %d != %d\n", + bcregx->operands[0].reg, NUPPC_REG_CRF0); + + return false; + } + + return true; + } + + if (capstone_instruction->op_count == 1) + { + if (capstone_instruction->operands[0].type == PPC_OP_REG) + { + uint32_t new_reg = bcregx->operands[0].reg - NUPPC_REG_CRF0; + uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0; + + if (new_reg != cs_reg) + { + printf("bcregx2_equal capstone 1 op REG, new reg is %d != cs reg %d\n", + new_reg, cs_reg); + + return false; + } + + return true; + } + else if (capstone_instruction->operands[0].type == PPC_OP_IMM) + { + if (bcregx->operands[0].reg != NUPPC_REG_CRF0) + { + printf("bcregx2_equal capstone 1 op UIMM, new reg is %d != %d\n", + bcregx->operands[0].reg, NUPPC_REG_CRF0); + + return false; + } + + return true; + } + + printf("bcregx2_equal unexpected op0 %d (capstone)\n", + capstone_instruction->operands[0].type); + + return false; + } + + if (capstone_instruction->op_count == 2) + { + if (capstone_instruction->operands[0].type != PPC_OP_REG) + { + printf("bcregx2_equal capstone op0 type %d != %d\n", + capstone_instruction->operands[0].type, PPC_OP_REG); + + return false; + } + + uint32_t new_reg = bcregx->operands[0].reg - NUPPC_REG_CRF0; + uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0; + + if (new_reg != cs_reg) + { + printf("bcregx2_equal capstone 2 op REG/UIMM, new reg is %d != cs reg %d\n", + new_reg, cs_reg); + + return false; + } + + return true; + } + + printf("bcregx2_equal unexpected num ops %d (capstone)\n", + capstone_instruction->op_count); + + return false; +} + +bool bcregx3_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction, const OperandsList* bcregx) +{ + if (bcregx->numOperands != 0) + { + printf("bcregx3_equal unexpected num operands %ld != 0 (new)\n", + bcregx->numOperands); + + return false; + } + + if (capstone_instruction->op_count == 0) + { + return true; + } + else if (capstone_instruction->op_count == 1) + { + if (capstone_instruction->operands[0].type != PPC_OP_IMM) + { + printf("bcregx3_equal cs 1-op unexpected op0 type %d != %d\n", + capstone_instruction->operands[0].type, PPC_OP_IMM); + + return false; + } + + return true; + } + + printf("bcregx3_equal unexpected num operands %d (cs)\n", + capstone_instruction->op_count); + + return false; +} + +bool bcregx_crn_equal(csh handle, const cs_ppc* capstone_instruction, const Instruction* new_instruction) +{ + if (new_instruction->numOperands == 0) + { + if (capstone_instruction->op_count == 0) + { + return true; + } + + if (capstone_instruction->op_count == 1 && capstone_instruction->operands[0].type == PPC_OP_IMM) + { + return true; + } + + printf("bcregx_crn new has no ops but capstone has %d ops and op0 is type %d != %d\n", + capstone_instruction->op_count, capstone_instruction->operands[0].type, PPC_OP_IMM); + return false; + } + + if (new_instruction->numOperands != 1) + { + printf("bcregx_crn unknown number of arguments for new %ld\n", + new_instruction->numOperands); + + return false; + } + + if (new_instruction->operands[0].cls != PPC_OP_REG_CRFS) + { + printf("bcregx_crn unknown new op0 class %d\n", + new_instruction->operands[0].cls); + + return false; + } + + uint32_t new_reg = new_instruction->operands[0].reg - NUPPC_REG_CRF0; + + if (capstone_instruction->op_count == 0) + { + if (new_reg != 0) + { + printf("bcregx_crn capstone no ops, new reg %d != 0\n", + new_reg); + + return false; + } + + return true; + } + + // capstone: <op> [cr0] <unnecessary target address> or <op> <crX> + if (capstone_instruction->op_count == 1) + { + if (capstone_instruction->operands[0].type == PPC_OP_REG) + { + // capstone: <op> <crX> + uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0; + if (cs_reg != new_reg) + { + printf("bcregx_crn capstone 1 reg %d != new reg %d\n", + cs_reg, new_reg); + + return false; + + } + + return true; + } + else if (capstone_instruction->operands[0].type == PPC_OP_IMM) + { + // capstone: <op> <target> + if (new_reg != 0) + { + printf("bcregx_crn capstone just target, new reg %d != 0\n", + new_reg); + + return false; + } + + return true; + } + else + { + printf("bcregx_crn capstone 1-op unknown type %d\n", + capstone_instruction->operands[0].type); + + return false; + } + } + + if (capstone_instruction->op_count == 2) + { + if (capstone_instruction->operands[0].type != PPC_OP_REG || capstone_instruction->operands[1].type != PPC_OP_IMM) + { + printf("bcregx_crn capstone 2-op types %d/%d != %d/%d\n", + capstone_instruction->operands[0].type, + capstone_instruction->operands[1].type, + PPC_OP_REG, PPC_OP_IMM); + + return false; + } + + uint32_t cs_reg = capstone_instruction->operands[0].reg - PPC_REG_CR0; + if (cs_reg != new_reg) + { + printf("bcregx_crn capstone 2-op new reg %d != cs reg %d\n", + new_reg, cs_reg); + + return false; + } + + return true; + } + + printf("bcregx_crn unknown number of operands in capstone %d\n", + capstone_instruction->op_count); + + return false; +} + +#define ADDRESS 0x1000 + +int main(int argc, char* argv[]) +{ + csh handle; + cs_insn *cs_instruction; + Instruction new_instruction; + + int err = cs_open(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN, &handle); + if (err != CS_ERR_OK) + { + printf("failed to open capstone: err %d\n", err); + return -1; + } + + err = cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON); + if (err != CS_ERR_OK) + { + printf("failed to set detail on: err %d\n", err); + return -1; + } + + uint32_t i; + + for (i = 0x7c000000; i < 0x80000000; ++i) + { + uint32_t op = ((i << 24) & 0xff000000) | ((i << 8) & 0x00ff0000) | ((i >> 8) & 0x0000ff00) | ((i >> 24) & 0x000000ff); + + bool cs_error = cs_disasm(handle, (uint8_t*)&op, sizeof op, ADDRESS, 1, &cs_instruction) != 1; + bool new_error = !Decompose32(&new_instruction, i, ADDRESS, DECODE_FLAGS_ALTIVEC | DECODE_FLAGS_PPC64 | DECODE_FLAGS_VSX); + + if (cs_error != new_error) + { + if (new_error) + { + // capstone disassembled something that we don't + bool complain = true; + + switch (cs_instruction->id) + { + // capstone is too eager to decode some instructions + case PPC_INS_MFSR: + case PPC_INS_MTSR: + if ((i & 0x0010f801) != 0) + complain = false; + break; + case PPC_INS_MFSRIN: + case PPC_INS_MTSRIN: + if ((i & 0x001f0001) != 0) + complain = false; + break; + case PPC_INS_WRTEE: + if ((i & 0x001ff801) != 0) + complain = false; + break; + case PPC_INS_WRTEEI: + if ((i & 0x03ff7801) != 0) + complain = false; + break; + case PPC_INS_MBAR: + case PPC_INS_MTMSR: + case PPC_INS_MTMSRD: + if ((i & 0x001ff801) != 0) + complain = false; + break; + case PPC_INS_DCCCI: + case PPC_INS_ICCCI: + if ((i & 0x021ff801) != 0) + complain = false; + break; + + case PPC_INS_TLBSX: + // capstone thinks this has an "RC" bits + if ((i & 0x1) != 0) + complain = false; + + // capstone is too eager to decode + if ((i & 0x03e00000) != 0) + complain = false; + + break; + + case PPC_INS_SC: + // capstone is too eager for sc + if ((i & 0x03fff01d) != 0) + complain = false; + + break; + + // capstone treats UIM as 5 bits when it's 4, + // with a reserved bit that should be clear + case PPC_INS_VEXTRACTD: + case PPC_INS_VEXTRACTUB: + case PPC_INS_VEXTRACTUH: + case PPC_INS_VEXTRACTUW: + case PPC_INS_VINSERTB: + case PPC_INS_VINSERTD: + case PPC_INS_VINSERTH: + case PPC_INS_VINSERTW: + case PPC_INS_XXEXTRACTUW: + case PPC_INS_XXINSERTW: + if ((i & 0x00100000) != 0) + complain = false; + + break; + + // capstone has the wrong opcode for this (it's 0x18c, not 0x18d) + case PPC_INS_ICBLQ: + if ((i & 0x1) == 0) + complain = false; + + break; + + case PPC_INS_COPY: + // capstone doesn't check that bit 10 == 1 + if (((i >> 21) & 0x1f) != 1) + complain = false; + + break; + + case PPC_INS_PASTE: + // capstone doesn't check that bit 10 == 1 or that bit 31 == 1 + if ((((i >> 21) & 0x1f) != 1) || ((i & 0x1) != 1)) + complain = false; + + break; + + case PPC_INS_LDMX: + // this instruction never made it into POWER9: + // https://inbox.sourceware.org/binutils/c3a53df0-cdf4-de7b-0e50-75150f2fa456@linux.ibm.com/T/ + // I guess we could add support, but it's something that would + // only apply to like pre-release binaries + complain = false; + break; + + case PPC_INS_DCBZLEP: + // I can't find any official docs about this + complain = false; + break; + + case PPC_INS_DCBF: + // L is only 2 bits, capstone recognizes more + if (((i >> 21) & 0x1f) > 3) + complain = false; + + break; + + default: + ; + } + + if (complain) + printf("capstone succeeded but new failed for %08x: %s %s [id %d]\n", + i, cs_instruction->mnemonic, cs_instruction->op_str, cs_instruction->id); + + cs_free(cs_instruction, 1); + } + else + { + // we disassembled something that capstone doesn't + bool complain = true; + + switch (new_instruction.id) + { + // capstone doesn't seem to handle these + case PPC_ID_ECIWX: + case PPC_ID_ECOWX: + case PPC_ID_FCMPO: + case PPC_ID_LSWX: + case PPC_ID_STSWX: + case PPC_ID_TLBIA: + case PPC_ID_STDEPX: + complain = false; + break; + + // capstone doesn't seem to handle "o" suffix + case PPC_ID_ADDx: + case PPC_ID_ADDCx: + case PPC_ID_ADDEx: + case PPC_ID_ADDMEx: + case PPC_ID_ADDZEx: + case PPC_ID_DIVDx: + case PPC_ID_DIVDEx: + case PPC_ID_DIVDEUx: + case PPC_ID_DIVDUx: + case PPC_ID_DIVWx: + case PPC_ID_DIVWEx: + case PPC_ID_DIVWEUx: + case PPC_ID_DIVWUx: + case PPC_ID_MULLDx: + case PPC_ID_MULLWx: + case PPC_ID_NEGx: + case PPC_ID_SUBFx: + case PPC_ID_SUBFCx: + case PPC_ID_SUBFEx: + case PPC_ID_SUBFMEx: + case PPC_ID_SUBFZEx: + if (new_instruction.flags.oe) + complain = false; + break; + + // capstone doesn't realize these have rc + case PPC_ID_MTFSB0x: + case PPC_ID_MTFSB1x: + if (new_instruction.flags.rc) + complain = false; + break; + + // capstone doesn't recognize op in DCI, ICI + case PPC_ID_DCI: + case PPC_ID_ICI: + if ((i & 0x01e00000) != 0) + complain = false; + break; + + // capstone doesn't recognize these + case PPC_ID_AV_BCDADD: + case PPC_ID_AV_BCDSUB: + complain = false; + break; + + // capstone has the wrong opcode: 0x18c instead of 0x18d + case PPC_ID_ICBLQ: + if ((i & 0x1) != 0) + complain = false; + break; + + case PPC_ID_SLBMFEV: + // v3.0B includes L bit, capstone still using V2.07 form + // which doesn't have it + if (((i >> 16) & 0x1) == 1) + complain = false; + break; + + case PPC_ID_DCBFEP: + // capstone doesn't recognize L!=0 + if (((i >> 21) & 0x3) != 0) + complain = false; + + break; + + default: + ; + } + + if (complain) + printf("new succeeded but capstone failed for %08x (%s)\n", i, GetMnemonic(&new_instruction)); + + + } + + continue; + } + + if (cs_error) + { + continue; + } + + const char* new_mnem = GetMnemonic(&new_instruction); + if (!new_mnem) + { + printf("no mnem for %08x (capstone %s)\n", i, cs_instruction->mnemonic); + cs_free(cs_instruction, 1); + continue; + } + + if (strcmp(cs_instruction->mnemonic, new_mnem)) + { + bool complain = true; + + switch (new_instruction.id) + { + case PPC_ID_BCCTRx: + { + uint32_t bo = new_instruction.operands[0].uimm; + if ((bo & 0x4) == 0) + complain = false; + + // "always branch" is 1z1zz, but + // capstone disassembles it as "bdnzctr"? + if ((bo & 0x14) == 0x14) + complain = false; + + break; + } + + case PPC_ID_BCLRx: + { + uint32_t bo = new_instruction.operands[0].uimm; + + // "always branch" is 1z1zz, but + // capstone disassembles it as "bdnzlr"? + if ((bo & 0x14) == 0x14) + complain = false; + + break; + } + + // capstone disassembles this as just "cntlz" + case PPC_ID_CNTLZWx: + complain = false; + break; + + // capstone disassembles pseudo-ops for RLWINM + // differently from RLWINM. for some reason + case PPC_ID_SLWIx: + if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rotlwi.")) + complain = false; + + // intentional fallthrough + case PPC_ID_SRWIx: + if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rlwinm.")) + complain = false; + + break; + + // likewise for RLDICR vs RLDICR. + case PPC_ID_SLDIx: + if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rldicr.")) + complain = false; + + break; + + // capstone doesn't seem to recognize CLRRWI + case PPC_ID_CLRRWIx: + complain = false; + break; + + case PPC_ID_MFSPR: + complain = !strncmp(cs_instruction->mnemonic, "mf", 3); + break; + + case PPC_ID_MTSPR: + complain = !strncmp(cs_instruction->mnemonic, "mt", 3); + break; + + default: + ; + } + + if (complain) + { + printf("different mnemonics for %08x! CS: %s NEW: %s\n", + i, cs_instruction->mnemonic, new_mnem); + + cs_free(cs_instruction, 1); + continue; + } + } + + cs_ppc* capstone_ppc = &cs_instruction->detail->ppc; + switch (new_instruction.id) + { + case PPC_ID_BCx: + { + OperandsList bcx; + FillBcxOperands(&bcx, &new_instruction); + + uint32_t bo = new_instruction.operands[0].uimm; + + switch (bo & 0x1e) + { + case 0: + case 2: + case 8: + case 10: + if (!(bcx_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS))) + { + printf("bcx different for %08x (new %s/cs %s %s)!\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + break; + + case 4: + case 6: + case 12: + case 14: + if (!(bcx_2op_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS))) + { + printf("bcx 2op different for %08x (new %s/cs %s %s)!\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + break; + + case 16: + case 18: + case 20: + case 22: + case 24: + case 26: + case 28: + case 30: + if (!(bcx_1op_equal(handle, capstone_ppc, &new_instruction, &bcx, ADDRESS))) + { + printf("bcx simple different for %08x (new %s/cs %s %s)!\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + break; + + default: + { + if (capstone_ppc->op_count != new_instruction.numOperands) + { + printf("bcx raw num ops different for %08x (new/cs %ld/%d)\n", + i, new_instruction.numOperands, capstone_ppc->op_count); + } + + unsigned int j; + for (j = 0; j < new_instruction.numOperands; ++j) + { + cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]); + Operand* new_op = &(new_instruction.operands[j]); + + if (!ops_equal(handle, capstone_op, new_op)) + { + printf("bcx raw op%d for %08x (new %s/cs %s %s)!\n", + j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + } + + break; + } + } + + cs_free(cs_instruction, 1); + continue; + } + + case PPC_ID_BCCTRx: + { + OperandsList bcctrx; + FillBcctrxOperands(&bcctrx, &new_instruction); + + uint32_t bo = new_instruction.operands[0].uimm; + + switch (bo & 0x1e) + { + case 4: + case 6: + case 12: + case 14: + if (!(bcregx2_equal(handle, capstone_ppc, &new_instruction, &bcctrx))) + { + printf("bcctrx not equal for %08x (new/cs %s/%s %s)\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + break; + + + default: + { + // invalid for BCCTRx + if ((bo & 0x4) == 0) + break; + + // capstone's "branch always" (BO: 1z1zz) is just + // flat out wrong? + if ((bo & 0x14) == 0x14) + break; + + if (capstone_ppc->op_count != new_instruction.numOperands) + { + printf("bcctrx raw num ops different for %08x (new/cs %ld/%d)\n", + i, new_instruction.numOperands, capstone_ppc->op_count); + } + + unsigned int j; + for (j = 0; j < new_instruction.numOperands; ++j) + { + cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]); + Operand* new_op = &(new_instruction.operands[j]); + + if (!ops_equal(handle, capstone_op, new_op)) + { + printf("bcctrx raw op%d for %08x (new %s/cs %s %s)!\n", + j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + } + } + } + + cs_free(cs_instruction, 1); + continue; + } + + case PPC_ID_BCLRx: + { + OperandsList bclrx; + FillBclrxOperands(&bclrx, &new_instruction); + + uint32_t bo = new_instruction.operands[0].uimm; + + switch (bo & 0x1e) + { + case 0: + case 2: + case 8: + case 10: + if (!(bcregx1_equal(handle, capstone_ppc, &new_instruction, &bclrx))) + { + printf("bcx different for %08x (new %s/cs %s %s)!\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + break; + + case 4: + case 6: + case 12: + case 14: + if (!(bcregx2_equal(handle, capstone_ppc, &new_instruction, &bclrx))) + { + printf("bclrx not equal for %08x (new/cs %s/%s %s)\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + break; + + case 16: + case 18: + case 24: + case 26: + if (!(bcregx3_equal(handle, capstone_ppc, &new_instruction, &bclrx))) + { + printf("bclrx not equal for %08x (new/cs %s/%s %s)\n", + i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + break; + + default: + // capstone's "branch always" is just flat out wrong? + if ((bo & 0x14) == 0x14) + break; + + if (capstone_ppc->op_count != new_instruction.numOperands) + { + printf("bclrx raw num ops different for %08x (new/cs %ld/%d)\n", + i, new_instruction.numOperands, capstone_ppc->op_count); + } + + unsigned int j; + for (j = 0; j < new_instruction.numOperands; ++j) + { + cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]); + Operand* new_op = &(new_instruction.operands[j]); + + if (!ops_equal(handle, capstone_op, new_op)) + { + printf("bclrx raw op%d for %08x (new %s/cs %s %s)!\n", + j, i, new_mnem, cs_instruction->mnemonic, cs_instruction->op_str); + } + + } + } + + cs_free(cs_instruction, 1); + continue; + } + + default: + ; + } + + if (capstone_ppc->op_count != new_instruction.numOperands) + { + bool complain = true; + + switch (new_instruction.id) + { + // capstone seems to think it only has one + // operand (despite printing 2?) + case PPC_ID_MFOCRF: + case PPC_ID_MTOCRF: + complain = false; + break; + + // capstone doesn't recognize the 0/1 operand it seems + case PPC_ID_VSX_XXSPLTD: + complain = false; + break; + + case PPC_ID_SLWIx: + case PPC_ID_SRWIx: + if (new_instruction.id == PPC_ID_SLWIx && new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rotlwi.")) + complain = false; + + if (new_instruction.flags.rc && !strcmp(cs_instruction->mnemonic, "rlwinm.")) + complain = false; + + break; + + case PPC_ID_CLRRWIx: + complain = false; + break; + + // despite printing 3 operands, capstone only thinks there + // are 2? + case PPC_ID_SLDIx: + complain = false; + break; + + // capstone doesn't recognize rS? + case PPC_ID_TLBIE: + complain = false; + break; + + // we treat "MFSPR" and "MF<some register>" the same, + // which have different number of arguments + // (MFSPR rD, UIMM vs. MFxxx rD) + case PPC_ID_MFSPR: + complain = false; + break; + + // we treat "MTSPR" and "MT<some register>" the same, + // which have different number of arguments + // (MTSPR UIMM, rS vs. MTxxx rS) + case PPC_ID_MTSPR: + complain = false; + break; + + // capstone treats DCCCI/ICCCI as <op> r0, r0? + case PPC_ID_DCCCI: + case PPC_ID_ICCCI: + complain = false; + break; + + // we unconditionally use cr0 and only omit it + // in disassembly + case PPC_ID_CMPD: + case PPC_ID_CMPDI: + case PPC_ID_CMPLD: + case PPC_ID_CMPLDI: + case PPC_ID_CMPLW: + case PPC_ID_CMPLWI: + case PPC_ID_CMPW: + case PPC_ID_CMPWI: + complain = false; + break; + + // these seem to treat bit 10 as an operand, when + // v3.0B requires it as a constant 1 in decoding + case PPC_ID_COPY: + case PPC_ID_PASTE: + complain = false; + break; + + default: + complain = true; + } + + if (complain) + { + printf("different number of operands for %08x (%s)! CS %d NEW %ld [%s] \n", + i, new_mnem, capstone_ppc->op_count, new_instruction.numOperands, + cs_instruction->op_str); + } + + // we unconditionally finish here since it's not super + // clear which operands we should compare to which + cs_free(cs_instruction, 1); + continue; + } + + unsigned int j; + for (j = 0; j < new_instruction.numOperands; ++j) + { + cs_ppc_op* capstone_op = &(capstone_ppc->operands[j]); + Operand* new_op = &(new_instruction.operands[j]); + + switch (new_instruction.id) + { + // things we sign extend to 64-bit but capstone + // doesn't + case PPC_ID_TDEQI: + case PPC_ID_TDGTI: + case PPC_ID_TDLGTI: + case PPC_ID_TDLLTI: + case PPC_ID_TDLTI: + case PPC_ID_TDNEI: + case PPC_ID_TDUI: + case PPC_ID_TWEQI: + case PPC_ID_TWGTI: + case PPC_ID_TWGEI: + case PPC_ID_TWLEI: + case PPC_ID_TWLLEI: + case PPC_ID_TWLGTI: + case PPC_ID_TWLLTI: + case PPC_ID_TWLTI: + case PPC_ID_TWNEI: + case PPC_ID_TWUI: + case PPC_ID_LI: + case PPC_ID_LIS: + if (j == 1) continue; + break; + + // things we sign extend to 64-bit but capstone + // doesn't + case PPC_ID_TDI: + case PPC_ID_TWI: + case PPC_ID_MULLI: + case PPC_ID_SUBFIC: + case PPC_ID_ADDI: + case PPC_ID_ADDICx: + case PPC_ID_ADDIS: + case PPC_ID_TABORTDCI: + case PPC_ID_TABORTWCI: + if (j == 2) continue; + break; + + // capstone sign extends the immediate for some + // reason + case PPC_ID_Bx: + continue; + + // capstone doesn't sign-extend these imms when + // it should; we also unconditionally decode cr0 + case PPC_ID_CMPDI: + case PPC_ID_CMPWI: + if (new_op->cls == PPC_OP_SIMM) continue; + if (new_op->cls == PPC_OP_REG_CRFD_IMPLY0 && new_op->reg == NUPPC_REG_CRF0) continue; + break; + + // we unconditionally decode cr0 + case PPC_ID_CMPLDI: + case PPC_ID_CMPLWI: + if (new_op->cls == PPC_OP_REG_CRFD_IMPLY0 && new_op->reg == NUPPC_REG_CRF0) continue; + break; + + // capstone makes operand 3 a register for some + // reason + case PPC_ID_ISEL: + if (j == 3) continue; + break; + + // capstone doesn't add 0/1 operand + case PPC_ID_VSX_XXSPLTD: + if (j == 2) continue; + break; + + // capstone sometimes uses RA instead of RA|0 + case PPC_ID_LBZCIX: + case PPC_ID_LDCIX: + case PPC_ID_LHZCIX: + case PPC_ID_LWZCIX: + case PPC_ID_STBCIX: + case PPC_ID_STDCIX: + case PPC_ID_STHCIX: + case PPC_ID_STWCIX: + if (j == 1) + { + if (new_op->cls == PPC_OP_UIMM && new_op->uimm == 0 && capstone_op->type == PPC_OP_REG && capstone_op->reg == PPC_REG_R0) + continue; + } + break; + + // capstone treats these as setting a CR bit (ie cr4+eq), but + // these instructions clear the rest of the CR field, so it + // should really be a CR register (ie cr4) + case PPC_ID_CMPEQB: + case PPC_ID_CMPRB: + if (j == 0) + continue; + + break; + + // capstone seems to swap the "dc" and "dm" bits + case PPC_ID_VSX_XVTSTDCDP: + case PPC_ID_VSX_XVTSTDCSP: + if (j == 2) + continue; + + break; + + // capstone thinks this is a floating point register + // (but it could be the weird "altivec/floating point + // registers and vsx registers are 2 sides of the same + // coin" thing) + case PPC_ID_VSX_XSIEXPQP: + if (j == 2) + continue; + break; + + default: ; + } + + if (!ops_equal(handle, capstone_op, new_op)) + { + printf("operand %d differs for %08x (%s)!\n", + j, i, new_mnem); + + break; + } + } + + cs_free(cs_instruction, 1); + } + + return 0; +} |
