/* Capstone Disassembly Engine */ /* By Nguyen Anh Quynh , 2013-2015 */ #ifdef CAPSTONE_HAS_POWERPC #include // debug #include #include "../../utils.h" #include "PPCMapping.h" #define GET_INSTRINFO_ENUM #include "PPCGenInstrInfo.inc" // NOTE: this reg_name_maps[] reflects the order of registers in ppc_reg static const name_map reg_name_maps[] = { { PPC_REG_INVALID, NULL }, { PPC_REG_CARRY, "ca" }, { PPC_REG_CTR, "ctr" }, { PPC_REG_LR, "lr" }, { PPC_REG_RM, "rm" }, { PPC_REG_VRSAVE, "vrsave" }, { PPC_REG_XER, "xer" }, { PPC_REG_ZERO, "zero" }, { PPC_REG_CR0, "cr0" }, { PPC_REG_CR1, "cr1" }, { PPC_REG_CR2, "cr2" }, { PPC_REG_CR3, "cr3" }, { PPC_REG_CR4, "cr4" }, { PPC_REG_CR5, "cr5" }, { PPC_REG_CR6, "cr6" }, { PPC_REG_CR7, "cr7" }, { PPC_REG_CTR8, "ctr8" }, { PPC_REG_F0, "f0" }, { PPC_REG_F1, "f1" }, { PPC_REG_F2, "f2" }, { PPC_REG_F3, "f3" }, { PPC_REG_F4, "f4" }, { PPC_REG_F5, "f5" }, { PPC_REG_F6, "f6" }, { PPC_REG_F7, "f7" }, { PPC_REG_F8, "f8" }, { PPC_REG_F9, "f9" }, { PPC_REG_F10, "f10" }, { PPC_REG_F11, "f11" }, { PPC_REG_F12, "f12" }, { PPC_REG_F13, "f13" }, { PPC_REG_F14, "f14" }, { PPC_REG_F15, "f15" }, { PPC_REG_F16, "f16" }, { PPC_REG_F17, "f17" }, { PPC_REG_F18, "f18" }, { PPC_REG_F19, "f19" }, { PPC_REG_F20, "f20" }, { PPC_REG_F21, "f21" }, { PPC_REG_F22, "f22" }, { PPC_REG_F23, "f23" }, { PPC_REG_F24, "f24" }, { PPC_REG_F25, "f25" }, { PPC_REG_F26, "f26" }, { PPC_REG_F27, "f27" }, { PPC_REG_F28, "f28" }, { PPC_REG_F29, "f29" }, { PPC_REG_F30, "f30" }, { PPC_REG_F31, "f31" }, { PPC_REG_LR8, "lr8" }, { PPC_REG_Q0, "q0" }, { PPC_REG_Q1, "q1" }, { PPC_REG_Q2, "q2" }, { PPC_REG_Q3, "q3" }, { PPC_REG_Q4, "q4" }, { PPC_REG_Q5, "q5" }, { PPC_REG_Q6, "q6" }, { PPC_REG_Q7, "q7" }, { PPC_REG_Q8, "q8" }, { PPC_REG_Q9, "q9" }, { PPC_REG_Q10, "q10" }, { PPC_REG_Q11, "q11" }, { PPC_REG_Q12, "q12" }, { PPC_REG_Q13, "q13" }, { PPC_REG_Q14, "q14" }, { PPC_REG_Q15, "q15" }, { PPC_REG_Q16, "q16" }, { PPC_REG_Q17, "q17" }, { PPC_REG_Q18, "q18" }, { PPC_REG_Q19, "q19" }, { PPC_REG_Q20, "q20" }, { PPC_REG_Q21, "q21" }, { PPC_REG_Q22, "q22" }, { PPC_REG_Q23, "q23" }, { PPC_REG_Q24, "q24" }, { PPC_REG_Q25, "q25" }, { PPC_REG_Q26, "q26" }, { PPC_REG_Q27, "q27" }, { PPC_REG_Q28, "q28" }, { PPC_REG_Q29, "q29" }, { PPC_REG_Q30, "q30" }, { PPC_REG_Q31, "q31" }, { PPC_REG_R0, "r0" }, { PPC_REG_R1, "r1" }, { PPC_REG_R2, "r2" }, { PPC_REG_R3, "r3" }, { PPC_REG_R4, "r4" }, { PPC_REG_R5, "r5" }, { PPC_REG_R6, "r6" }, { PPC_REG_R7, "r7" }, { PPC_REG_R8, "r8" }, { PPC_REG_R9, "r9" }, { PPC_REG_R10, "r10" }, { PPC_REG_R11, "r11" }, { PPC_REG_R12, "r12" }, { PPC_REG_R13, "r13" }, { PPC_REG_R14, "r14" }, { PPC_REG_R15, "r15" }, { PPC_REG_R16, "r16" }, { PPC_REG_R17, "r17" }, { PPC_REG_R18, "r18" }, { PPC_REG_R19, "r19" }, { PPC_REG_R20, "r20" }, { PPC_REG_R21, "r21" }, { PPC_REG_R22, "r22" }, { PPC_REG_R23, "r23" }, { PPC_REG_R24, "r24" }, { PPC_REG_R25, "r25" }, { PPC_REG_R26, "r26" }, { PPC_REG_R27, "r27" }, { PPC_REG_R28, "r28" }, { PPC_REG_R29, "r29" }, { PPC_REG_R30, "r30" }, { PPC_REG_R31, "r31" }, { PPC_REG_V0, "v0" }, { PPC_REG_V1, "v1" }, { PPC_REG_V2, "v2" }, { PPC_REG_V3, "v3" }, { PPC_REG_V4, "v4" }, { PPC_REG_V5, "v5" }, { PPC_REG_V6, "v6" }, { PPC_REG_V7, "v7" }, { PPC_REG_V8, "v8" }, { PPC_REG_V9, "v9" }, { PPC_REG_V10, "v10" }, { PPC_REG_V11, "v11" }, { PPC_REG_V12, "v12" }, { PPC_REG_V13, "v13" }, { PPC_REG_V14, "v14" }, { PPC_REG_V15, "v15" }, { PPC_REG_V16, "v16" }, { PPC_REG_V17, "v17" }, { PPC_REG_V18, "v18" }, { PPC_REG_V19, "v19" }, { PPC_REG_V20, "v20" }, { PPC_REG_V21, "v21" }, { PPC_REG_V22, "v22" }, { PPC_REG_V23, "v23" }, { PPC_REG_V24, "v24" }, { PPC_REG_V25, "v25" }, { PPC_REG_V26, "v26" }, { PPC_REG_V27, "v27" }, { PPC_REG_V28, "v28" }, { PPC_REG_V29, "v29" }, { PPC_REG_V30, "v30" }, { PPC_REG_V31, "v31" }, { PPC_REG_VS0, "vs0" }, { PPC_REG_VS1, "vs1" }, { PPC_REG_VS2, "vs2" }, { PPC_REG_VS3, "vs3" }, { PPC_REG_VS4, "vs4" }, { PPC_REG_VS5, "vs5" }, { PPC_REG_VS6, "vs6" }, { PPC_REG_VS7, "vs7" }, { PPC_REG_VS8, "vs8" }, { PPC_REG_VS9, "vs9" }, { PPC_REG_VS10, "vs10" }, { PPC_REG_VS11, "vs11" }, { PPC_REG_VS12, "vs12" }, { PPC_REG_VS13, "vs13" }, { PPC_REG_VS14, "vs14" }, { PPC_REG_VS15, "vs15" }, { PPC_REG_VS16, "vs16" }, { PPC_REG_VS17, "vs17" }, { PPC_REG_VS18, "vs18" }, { PPC_REG_VS19, "vs19" }, { PPC_REG_VS20, "vs20" }, { PPC_REG_VS21, "vs21" }, { PPC_REG_VS22, "vs22" }, { PPC_REG_VS23, "vs23" }, { PPC_REG_VS24, "vs24" }, { PPC_REG_VS25, "vs25" }, { PPC_REG_VS26, "vs26" }, { PPC_REG_VS27, "vs27" }, { PPC_REG_VS28, "vs28" }, { PPC_REG_VS29, "vs29" }, { PPC_REG_VS30, "vs30" }, { PPC_REG_VS31, "vs31" }, { PPC_REG_VS32, "vs32" }, { PPC_REG_VS33, "vs33" }, { PPC_REG_VS34, "vs34" }, { PPC_REG_VS35, "vs35" }, { PPC_REG_VS36, "vs36" }, { PPC_REG_VS37, "vs37" }, { PPC_REG_VS38, "vs38" }, { PPC_REG_VS39, "vs39" }, { PPC_REG_VS40, "vs40" }, { PPC_REG_VS41, "vs41" }, { PPC_REG_VS42, "vs42" }, { PPC_REG_VS43, "vs43" }, { PPC_REG_VS44, "vs44" }, { PPC_REG_VS45, "vs45" }, { PPC_REG_VS46, "vs46" }, { PPC_REG_VS47, "vs47" }, { PPC_REG_VS48, "vs48" }, { PPC_REG_VS49, "vs49" }, { PPC_REG_VS50, "vs50" }, { PPC_REG_VS51, "vs51" }, { PPC_REG_VS52, "vs52" }, { PPC_REG_VS53, "vs53" }, { PPC_REG_VS54, "vs54" }, { PPC_REG_VS55, "vs55" }, { PPC_REG_VS56, "vs56" }, { PPC_REG_VS57, "vs57" }, { PPC_REG_VS58, "vs58" }, { PPC_REG_VS59, "vs59" }, { PPC_REG_VS60, "vs60" }, { PPC_REG_VS61, "vs61" }, { PPC_REG_VS62, "vs62" }, { PPC_REG_VS63, "vs63" }, { PPC_REG_CR0EQ, "cr0eq" }, { PPC_REG_CR1EQ, "cr1eq" }, { PPC_REG_CR2EQ, "cr2eq" }, { PPC_REG_CR3EQ, "cr3eq" }, { PPC_REG_CR4EQ, "cr4eq" }, { PPC_REG_CR5EQ, "cr5eq" }, { PPC_REG_CR6EQ, "cr6eq" }, { PPC_REG_CR7EQ, "cr7eq" }, { PPC_REG_CR0GT, "cr0gt" }, { PPC_REG_CR1GT, "cr1gt" }, { PPC_REG_CR2GT, "cr2gt" }, { PPC_REG_CR3GT, "cr3gt" }, { PPC_REG_CR4GT, "cr4gt" }, { PPC_REG_CR5GT, "cr5gt" }, { PPC_REG_CR6GT, "cr6gt" }, { PPC_REG_CR7GT, "cr7gt" }, { PPC_REG_CR0LT, "cr0lt" }, { PPC_REG_CR1LT, "cr1lt" }, { PPC_REG_CR2LT, "cr2lt" }, { PPC_REG_CR3LT, "cr3lt" }, { PPC_REG_CR4LT, "cr4lt" }, { PPC_REG_CR5LT, "cr5lt" }, { PPC_REG_CR6LT, "cr6lt" }, { PPC_REG_CR7LT, "cr7lt" }, { PPC_REG_CR0UN, "cr0un" }, { PPC_REG_CR1UN, "cr1un" }, { PPC_REG_CR2UN, "cr2un" }, { PPC_REG_CR3UN, "cr3un" }, { PPC_REG_CR4UN, "cr4un" }, { PPC_REG_CR5UN, "cr5un" }, { PPC_REG_CR6UN, "cr6un" }, { PPC_REG_CR7UN, "cr7un" }, }; const char *PPC_reg_name(csh handle, unsigned int reg) { // binary searching since the IDs are sorted in order unsigned int left, right, m; unsigned int max = ARR_SIZE(reg_name_maps); right = max - 1; if (reg < reg_name_maps[0].id || reg > reg_name_maps[right].id) // not found return NULL; left = 0; while(left <= right) { m = (left + right) / 2; if (reg == reg_name_maps[m].id) { return reg_name_maps[m].name; } if (reg < reg_name_maps[m].id) right = m - 1; else left = m + 1; } // not found return NULL; } ppc_reg PPC_name_reg(const char *name) { unsigned int i; for(i = 1; i < ARR_SIZE(reg_name_maps); i++) { if (!strcmp(name, reg_name_maps[i].name)) return reg_name_maps[i].id; } // not found return 0; } static const insn_map insns[] = { // dummy item { 0, 0, #ifndef CAPSTONE_DIET { 0 }, { 0 }, { 0 }, 0, 0 #endif }, #include "PPCMappingInsn.inc" }; // given internal insn id, return public instruction info void PPC_get_insn_id(cs_struct *h, cs_insn *insn, unsigned int id) { int i; i = insn_find(insns, ARR_SIZE(insns), id, &h->insn_cache); if (i != 0) { insn->id = insns[i].mapid; if (h->detail) { #ifndef CAPSTONE_DIET cs_struct handle; handle.detail = h->detail; memcpy(insn->detail->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use)); insn->detail->regs_read_count = (uint8_t)count_positive(insns[i].regs_use); memcpy(insn->detail->regs_write, insns[i].regs_mod, sizeof(insns[i].regs_mod)); insn->detail->regs_write_count = (uint8_t)count_positive(insns[i].regs_mod); memcpy(insn->detail->groups, insns[i].groups, sizeof(insns[i].groups)); insn->detail->groups_count = (uint8_t)count_positive8(insns[i].groups); if (insns[i].branch || insns[i].indirect_branch) { // this insn also belongs to JUMP group. add JUMP group insn->detail->groups[insn->detail->groups_count] = PPC_GRP_JUMP; insn->detail->groups_count++; } insn->detail->ppc.update_cr0 = cs_reg_write((csh)&handle, insn, PPC_REG_CR0); #endif } } } static const char * const insn_name_maps[] = { NULL, // PPC_INS_BCT #include "PPCMappingInsnName.inc" }; const char *PPC_insn_name(csh handle, unsigned int id) { #ifndef CAPSTONE_DIET if (id >= PPC_INS_ENDING) return NULL; return insn_name_maps[id]; #else return NULL; #endif } // map instruction name to public instruction ID ppc_insn PPC_map_insn(const char *name) { unsigned int i; for(i = 1; i < ARR_SIZE(insn_name_maps); i++) { if (!strcmp(name, insn_name_maps[i])) return i; } // not found return PPC_INS_INVALID; } #ifndef CAPSTONE_DIET static const name_map group_name_maps[] = { // generic groups { PPC_GRP_INVALID, NULL }, { PPC_GRP_JUMP, "jump" }, // architecture-specific groups { PPC_GRP_ALTIVEC, "altivec" }, { PPC_GRP_MODE32, "mode32" }, { PPC_GRP_MODE64, "mode64" }, { PPC_GRP_BOOKE, "booke" }, { PPC_GRP_NOTBOOKE, "notbooke" }, { PPC_GRP_SPE, "spe" }, { PPC_GRP_VSX, "vsx" }, { PPC_GRP_E500, "e500" }, { PPC_GRP_PPC4XX, "ppc4xx" }, { PPC_GRP_PPC6XX, "ppc6xx" }, { PPC_GRP_ICBT, "icbt" }, { PPC_GRP_P8ALTIVEC, "p8altivec" }, { PPC_GRP_P8VECTOR, "p8vector" }, { PPC_GRP_QPX, "qpx" }, }; #endif const char *PPC_group_name(csh handle, unsigned int id) { #ifndef CAPSTONE_DIET return id2name(group_name_maps, ARR_SIZE(group_name_maps), id); #else return NULL; #endif } static const struct ppc_alias alias_insn_name_maps[] = { //{ PPC_INS_BTA, "bta" }, { PPC_INS_B, PPC_BC_LT, "blt" }, { PPC_INS_B, PPC_BC_LE, "ble" }, { PPC_INS_B, PPC_BC_EQ, "beq" }, { PPC_INS_B, PPC_BC_GE, "bge" }, { PPC_INS_B, PPC_BC_GT, "bgt" }, { PPC_INS_B, PPC_BC_NE, "bne" }, { PPC_INS_B, PPC_BC_UN, "bun" }, { PPC_INS_B, PPC_BC_NU, "bnu" }, { PPC_INS_B, PPC_BC_SO, "bso" }, { PPC_INS_B, PPC_BC_NS, "bns" }, { PPC_INS_BA, PPC_BC_LT, "blta" }, { PPC_INS_BA, PPC_BC_LE, "blea" }, { PPC_INS_BA, PPC_BC_EQ, "beqa" }, { PPC_INS_BA, PPC_BC_GE, "bgea" }, { PPC_INS_BA, PPC_BC_GT, "bgta" }, { PPC_INS_BA, PPC_BC_NE, "bnea" }, { PPC_INS_BA, PPC_BC_UN, "buna" }, { PPC_INS_BA, PPC_BC_NU, "bnua" }, { PPC_INS_BA, PPC_BC_SO, "bsoa" }, { PPC_INS_BA, PPC_BC_NS, "bnsa" }, { PPC_INS_BCTR, PPC_BC_LT, "bltctr" }, { PPC_INS_BCTR, PPC_BC_LE, "blectr" }, { PPC_INS_BCTR, PPC_BC_EQ, "beqctr" }, { PPC_INS_BCTR, PPC_BC_GE, "bgectr" }, { PPC_INS_BCTR, PPC_BC_GT, "bgtctr" }, { PPC_INS_BCTR, PPC_BC_NE, "bnectr" }, { PPC_INS_BCTR, PPC_BC_UN, "bunctr" }, { PPC_INS_BCTR, PPC_BC_NU, "bnuctr" }, { PPC_INS_BCTR, PPC_BC_SO, "bsoctr" }, { PPC_INS_BCTR, PPC_BC_NS, "bnsctr" }, { PPC_INS_BCTRL, PPC_BC_LT, "bltctrl" }, { PPC_INS_BCTRL, PPC_BC_LE, "blectrl" }, { PPC_INS_BCTRL, PPC_BC_EQ, "beqctrl" }, { PPC_INS_BCTRL, PPC_BC_GE, "bgectrl" }, { PPC_INS_BCTRL, PPC_BC_GT, "bgtctrl" }, { PPC_INS_BCTRL, PPC_BC_NE, "bnectrl" }, { PPC_INS_BCTRL, PPC_BC_UN, "bunctrl" }, { PPC_INS_BCTRL, PPC_BC_NU, "bnuctrl" }, { PPC_INS_BCTRL, PPC_BC_SO, "bsoctrl" }, { PPC_INS_BCTRL, PPC_BC_NS, "bnsctrl" }, { PPC_INS_BL, PPC_BC_LT, "bltl" }, { PPC_INS_BL, PPC_BC_LE, "blel" }, { PPC_INS_BL, PPC_BC_EQ, "beql" }, { PPC_INS_BL, PPC_BC_GE, "bgel" }, { PPC_INS_BL, PPC_BC_GT, "bgtl" }, { PPC_INS_BL, PPC_BC_NE, "bnel" }, { PPC_INS_BL, PPC_BC_UN, "bunl" }, { PPC_INS_BL, PPC_BC_NU, "bnul" }, { PPC_INS_BL, PPC_BC_SO, "bsol" }, { PPC_INS_BL, PPC_BC_NS, "bnsl" }, { PPC_INS_BLA, PPC_BC_LT, "bltla" }, { PPC_INS_BLA, PPC_BC_LE, "blela" }, { PPC_INS_BLA, PPC_BC_EQ, "beqla" }, { PPC_INS_BLA, PPC_BC_GE, "bgela" }, { PPC_INS_BLA, PPC_BC_GT, "bgtla" }, { PPC_INS_BLA, PPC_BC_NE, "bnela" }, { PPC_INS_BLA, PPC_BC_UN, "bunla" }, { PPC_INS_BLA, PPC_BC_NU, "bnula" }, { PPC_INS_BLA, PPC_BC_SO, "bsola" }, { PPC_INS_BLA, PPC_BC_NS, "bnsla" }, { PPC_INS_BLR, PPC_BC_LT, "bltlr" }, { PPC_INS_BLR, PPC_BC_LE, "blelr" }, { PPC_INS_BLR, PPC_BC_EQ, "beqlr" }, { PPC_INS_BLR, PPC_BC_GE, "bgelr" }, { PPC_INS_BLR, PPC_BC_GT, "bgtlr" }, { PPC_INS_BLR, PPC_BC_NE, "bnelr" }, { PPC_INS_BLR, PPC_BC_UN, "bunlr" }, { PPC_INS_BLR, PPC_BC_NU, "bnulr" }, { PPC_INS_BLR, PPC_BC_SO, "bsolr" }, { PPC_INS_BLR, PPC_BC_NS, "bnslr" }, { PPC_INS_BLRL, PPC_BC_LT, "bltlrl" }, { PPC_INS_BLRL, PPC_BC_LE, "blelrl" }, { PPC_INS_BLRL, PPC_BC_EQ, "beqlrl" }, { PPC_INS_BLRL, PPC_BC_GE, "bgelrl" }, { PPC_INS_BLRL, PPC_BC_GT, "bgtlrl" }, { PPC_INS_BLRL, PPC_BC_NE, "bnelrl" }, { PPC_INS_BLRL, PPC_BC_UN, "bunlrl" }, { PPC_INS_BLRL, PPC_BC_NU, "bnulrl" }, { PPC_INS_BLRL, PPC_BC_SO, "bsolrl" }, { PPC_INS_BLRL, PPC_BC_NS, "bnslrl" }, }; // given alias mnemonic, return instruction ID & CC bool PPC_alias_insn(const char *name, struct ppc_alias *alias) { size_t i; alias->cc = PPC_BC_INVALID; for(i = 0; i < ARR_SIZE(alias_insn_name_maps); i++) { if (!strcmp(name, alias_insn_name_maps[i].mnem)) { // alias->id = alias_insn_name_maps[i].id; alias->cc = alias_insn_name_maps[i].cc; return true; } } // not found return false; } // check if this insn is relative branch bool PPC_abs_branch(cs_struct *h, unsigned int id) { unsigned int i; // list all absolute branch instructions static const 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, PPC_BDZLA, 0 }; // printf("opcode: %u\n", id); for (i = 0; insn_abs[i]; i++) { if (id == insn_abs[i]) { return true; } } // not found return false; } #endif