diff options
Diffstat (limited to 'capstone/arch/PowerPC/PPCMapping.c')
-rw-r--r-- | capstone/arch/PowerPC/PPCMapping.c | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/capstone/arch/PowerPC/PPCMapping.c b/capstone/arch/PowerPC/PPCMapping.c new file mode 100644 index 000000000..1ed84738c --- /dev/null +++ b/capstone/arch/PowerPC/PPCMapping.c @@ -0,0 +1,569 @@ +/* Capstone Disassembly Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013-2015 */ + +#ifdef CAPSTONE_HAS_POWERPC + +#include <stdio.h> // debug +#include <string.h> + +#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 |