| /* Capstone Disassembler Engine */ |
| /* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */ |
| |
| #include <stdio.h> |
| |
| #include <capstone/capstone.h> |
| #include "capstone/ppc.h" |
| #include "cstool.h" |
| |
| static const char* get_pred_name(ppc_pred pred) |
| { |
| switch(pred) { |
| default: |
| return ("invalid"); |
| case PPC_PRED_LT: |
| case PPC_PRED_LT_MINUS: |
| case PPC_PRED_LT_PLUS: |
| case PPC_PRED_LT_RESERVED: |
| return ("lt"); |
| case PPC_PRED_LE: |
| case PPC_PRED_LE_MINUS: |
| case PPC_PRED_LE_PLUS: |
| case PPC_PRED_LE_RESERVED: |
| return ("le"); |
| case PPC_PRED_EQ: |
| case PPC_PRED_EQ_MINUS: |
| case PPC_PRED_EQ_PLUS: |
| case PPC_PRED_EQ_RESERVED: |
| return ("eq"); |
| case PPC_PRED_GE: |
| case PPC_PRED_GE_MINUS: |
| case PPC_PRED_GE_PLUS: |
| case PPC_PRED_GE_RESERVED: |
| return ("ge"); |
| case PPC_PRED_GT: |
| case PPC_PRED_GT_MINUS: |
| case PPC_PRED_GT_PLUS: |
| case PPC_PRED_GT_RESERVED: |
| return ("gt"); |
| case PPC_PRED_NE: |
| case PPC_PRED_NE_MINUS: |
| case PPC_PRED_NE_PLUS: |
| case PPC_PRED_NE_RESERVED: |
| return ("ne"); |
| case PPC_PRED_UN: // PPC_PRED_SO |
| case PPC_PRED_UN_MINUS: |
| case PPC_PRED_UN_PLUS: |
| case PPC_PRED_UN_RESERVED: |
| return ("so/un"); |
| case PPC_PRED_NU: // PPC_PRED_NS |
| case PPC_PRED_NU_MINUS: |
| case PPC_PRED_NU_PLUS: |
| case PPC_PRED_NU_RESERVED: |
| return ("ns/nu"); |
| case PPC_PRED_NZ: |
| case PPC_PRED_NZ_MINUS: |
| case PPC_PRED_NZ_PLUS: |
| case PPC_PRED_NZ_RESERVED: |
| return ("nz"); |
| case PPC_PRED_Z: |
| case PPC_PRED_Z_MINUS: |
| case PPC_PRED_Z_PLUS: |
| case PPC_PRED_Z_RESERVED: |
| return ("z"); |
| case PPC_PRED_BIT_SET: |
| return "bit-set"; |
| case PPC_PRED_BIT_UNSET: |
| return "bit-unset"; |
| } |
| } |
| |
| static const char *get_pred_hint(ppc_br_hint at) { |
| switch (at) { |
| default: |
| return "invalid"; |
| case PPC_BR_NOT_GIVEN: |
| return "not-given"; |
| case PPC_BR_TAKEN: |
| return "likely-taken"; |
| case PPC_BR_NOT_TAKEN: |
| return "likely-not-taken"; |
| case PPC_BR_RESERVED: |
| return "reserved"; |
| } |
| } |
| |
| void print_insn_detail_ppc(csh handle, cs_insn *ins) |
| { |
| cs_ppc *ppc; |
| int i; |
| |
| // detail can be NULL on "data" instruction if SKIPDATA option is turned ON |
| if (ins->detail == NULL) |
| return; |
| |
| ppc = &(ins->detail->ppc); |
| if (ppc->op_count) |
| printf("\top_count: %u\n", ppc->op_count); |
| |
| for (i = 0; i < ppc->op_count; i++) { |
| cs_ppc_op *op = &(ppc->operands[i]); |
| switch((int)op->type) { |
| default: |
| break; |
| case PPC_OP_REG: |
| printf("\t\toperands[%u].type: REG = %s\n", i, cs_reg_name(handle, op->reg)); |
| break; |
| case PPC_OP_IMM: |
| printf("\t\toperands[%u].type: IMM = 0x%"PRIx64"\n", i, op->imm); |
| break; |
| case PPC_OP_MEM: |
| printf("\t\toperands[%u].type: MEM\n", i); |
| if (op->mem.base != PPC_REG_INVALID) |
| printf("\t\t\toperands[%u].mem.base: REG = %s\n", |
| i, cs_reg_name(handle, op->mem.base)); |
| if (op->mem.offset != PPC_REG_INVALID) |
| printf("\t\t\toperands[%u].mem.offset: REG = %s\n", i, |
| cs_reg_name(handle, op->mem.offset)); |
| if (op->mem.disp != 0) |
| printf("\t\t\toperands[%u].mem.disp: 0x%x\n", i, op->mem.disp); |
| |
| break; |
| } |
| switch(op->access) { |
| default: |
| break; |
| case CS_AC_READ: |
| printf("\t\toperands[%u].access: READ\n", i); |
| break; |
| case CS_AC_WRITE: |
| printf("\t\toperands[%u].access: WRITE\n", i); |
| break; |
| case CS_AC_READ_WRITE: |
| printf("\t\toperands[%u].access: READ | WRITE\n", i); |
| break; |
| } |
| } |
| |
| if (ppc->bc.pred_cr != PPC_PRED_INVALID || |
| ppc->bc.pred_ctr != PPC_PRED_INVALID) { |
| printf("\tBranch:\n"); |
| printf("\t\tbi: %u\n", ppc->bc.bi); |
| printf("\t\tbo: %u\n", ppc->bc.bo); |
| if (ppc->bc.bh != PPC_BH_INVALID) |
| printf("\t\tbh: %u\n", ppc->bc.bh); |
| if (ppc->bc.pred_cr != PPC_PRED_INVALID) { |
| printf("\t\tcrX: %s\n", cs_reg_name(handle, ppc->bc.crX)); |
| printf("\t\tpred CR-bit: %s\n", get_pred_name(ppc->bc.pred_cr)); |
| } |
| if (ppc->bc.pred_ctr != PPC_PRED_INVALID) |
| printf("\t\tpred CTR: %s\n", get_pred_name(ppc->bc.pred_ctr)); |
| if (ppc->bc.hint != PPC_BR_NOT_GIVEN) |
| printf("\t\thint: %s\n", get_pred_hint(ppc->bc.hint)); |
| } |
| |
| if (ppc->bc.hint != PPC_BR_NOT_GIVEN) |
| printf("\tBranch hint: %u\n", ppc->bc.hint); |
| |
| if (ppc->update_cr0) |
| printf("\tUpdate-CR0: True\n"); |
| |
| uint16_t *regs_read = ins->detail->regs_read; |
| uint16_t *regs_write = ins->detail->regs_write; |
| uint8_t regs_read_count = ins->detail->regs_read_count; |
| uint8_t regs_write_count = ins->detail->regs_write_count; |
| // Print out all registers accessed by this instruction (either implicit or explicit) |
| if (regs_read_count) { |
| printf("\tImplicit registers read:"); |
| for(i = 0; i < regs_read_count; i++) { |
| printf(" %s", cs_reg_name(handle, regs_read[i])); |
| } |
| printf("\n"); |
| } |
| |
| if (regs_write_count) { |
| printf("\tImplicit registers modified:"); |
| for(i = 0; i < regs_write_count; i++) { |
| printf(" %s", cs_reg_name(handle, regs_write[i])); |
| } |
| printf("\n"); |
| } |
| } |