arm64: handle decomposer properly for alias insn
diff --git a/arch/AArch64/mapping.c b/arch/AArch64/mapping.c
index e9652a5..895d2a2 100644
--- a/arch/AArch64/mapping.c
+++ b/arch/AArch64/mapping.c
@@ -1842,14 +1842,47 @@
{ AArch64_VCVTxu2f_4S, ARM64_INS_UCVTF, { 0 }, { 0 }, { ARM64_GRP_NEON, 0 } },
};
+// some alias instruction only need to be defined locally to satisfy
+// some lookup functions
+// just make sure these IDs never reuse any other IDs ARM_INS_*
+#define ARM64_INS_NEGS -1
+#define ARM64_INS_NGCS -2
+
+// all alias instructions & their semantic infos
+static insn_map alias_insns[] = {
+ { AArch64_MSUBwwww, ARM64_INS_MNEG, { 0 }, { 0 }, { 0 } },
+ { AArch64_UMSUBLxwwx, ARM64_INS_UMNEGL, { 0 }, { 0 }, { 0 } },
+ { AArch64_SMSUBLxwwx, ARM64_INS_SMNEGL, { 0 }, { 0 }, { 0 } },
+ // MOV can be mapped back to ADD or ORR, but its semantic info is always same
+ { AArch64_ADDwwi_lsl0_s, ARM64_INS_MOV, { 0 }, { 0 }, { 0 } },
+ // { AArch64_ADDxxi_lsl0_s, ARM64_INS_MOV, { 0 }, { 0 }, { 0 } },
+ // { AArch64_ORRwww_lsl, ARM64_INS_MOV, { 0 }, { 0 }, { 0 } },
+ // { AArch64_ORRxxx_lsl, ARM64_INS_MOV, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_NOP, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_YIELD, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_WFE, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_WFI, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_SEV, { 0 }, { 0 }, { 0 } },
+ { AArch64_HINTi, ARM64_INS_SEVL, { 0 }, { 0 }, { 0 } },
+ { AArch64_SBCwww, ARM64_INS_NGC, { ARM64_REG_NZCV, 0 }, { 0 }, { 0 } },
+ { AArch64_SBCSwww, ARM64_INS_NGCS, { ARM64_REG_NZCV, 0 }, { ARM64_REG_NZCV, 0 }, { 0 } },
+ { AArch64_SUBSwww_lsl, ARM64_INS_NEGS, { 0 }, { ARM64_REG_NZCV, 0 }, { 0 } },
+ // { AArch64_SUBSxxx_lsl, ARM64_INS_NEGS, { 0 }, { ARM64_REG_NZCV, 0 }, { 0 } },
+ { AArch64_SUBxxx_lsl, ARM64_INS_NEG, { 0 }, { 0 }, { 0 } },
+ // { AArch64_SUBwww_lsl, ARM64_INS_NEG, { 0 }, { 0 }, { 0 } },
+};
+
void AArch64_get_insn_id(cs_insn *insn, unsigned int id)
{
+ // try alias insn first
int i = insn_find(insns, ARR_SIZE(insns), id);
if (i != -1) {
insn->id = insns[i].mapid;
memcpy(insn->regs_read, insns[i].regs_use, sizeof(insns[i].regs_use));
memcpy(insn->regs_write, insns[i].regs_mod, sizeof(insns[i].regs_mod));
memcpy(insn->groups, insns[i].groups, sizeof(insns[i].groups));
+ // call cs_reg_write() with handle = 1 to pass handle check
+ // we only need to find if this insn modifies ARM64_REG_NZCV
insn->arm64.update_flags = cs_reg_write(1, insn, ARM64_REG_NZCV);
}
}
@@ -1857,7 +1890,11 @@
// given public insn id, return internal instruction ID
unsigned int AArch64_get_insn_id2(unsigned int id)
{
- return insn_reverse_id(insns, ARR_SIZE(insns), id);
+ unsigned int res = insn_reverse_id(insns, ARR_SIZE(insns), id);
+ if (!res) // is this alias insn?
+ res = insn_reverse_id(alias_insns, ARR_SIZE(alias_insns), id);
+
+ return res;
}
static name_map insn_name_maps[] = {
@@ -2217,51 +2254,56 @@
{ ARM64_INS_UXTH, "UXTH" },
};
+// map *S & alias instructions back to original id
+static name_map alias_insn_name_maps[] = {
+ { ARM64_INS_ADC, "ADCS" },
+ { ARM64_INS_AND, "ANDS" },
+ { ARM64_INS_ADD, "ADDS" },
+ { ARM64_INS_BIC, "BICS" },
+ { ARM64_INS_SBC, "SBCS" },
+ { ARM64_INS_SUB, "SUBS" },
+
+ // alias insn
+ { ARM64_INS_MNEG, "MNEG" },
+ { ARM64_INS_UMNEGL, "UMNEGL" },
+ { ARM64_INS_SMNEGL, "SMNEGL" },
+ { ARM64_INS_MOV, "MOV" },
+ { ARM64_INS_NOP, "NOP" },
+ { ARM64_INS_YIELD, "YIELD" },
+ { ARM64_INS_WFE, "WFE" },
+ { ARM64_INS_WFI, "WFI" },
+ { ARM64_INS_SEV, "SEV" },
+ { ARM64_INS_SEVL, "SEVL" },
+ { ARM64_INS_NGC, "NGC" },
+ { ARM64_INS_NGCS, "NGCS" },
+ { ARM64_INS_NEG, "NEG" },
+ { ARM64_INS_NEGS, "NEGS" },
+};
+
char *AArch64_insn_name(unsigned int id)
{
if (id >= ARM64_INS_MAX)
return NULL;
+ // try with alias insn first
+ int i;
+ for (i = 0; i < ARR_SIZE(alias_insn_name_maps); i++) {
+ if (alias_insn_name_maps[i].id == id)
+ return alias_insn_name_maps[i].name;
+ }
+
return insn_name_maps[id].name;
}
// map instruction name to public instruction ID
arm64_reg AArch64_map_insn(char *name)
{
- // map *S instructions back to original id
- name_map insn_name_maps2[] = {
- { ARM64_INS_ADC, "ADCS" },
- { ARM64_INS_AND, "ANDS" },
- { ARM64_INS_ADD, "ADDS" },
- { ARM64_INS_BIC, "BICS" },
- { ARM64_INS_SBC, "SBCS" },
- { ARM64_INS_SUB, "SUBS" },
-
- // alias insn
- { ARM64_INS_MNEG, "MNEG" },
- { ARM64_INS_UMNEGL, "UMNEGL" },
- { ARM64_INS_SMNEGL, "SMNEGL" },
- { ARM64_INS_MOV, "MOV" },
- { ARM64_INS_NOP, "NOP" },
- { ARM64_INS_YIELD, "YIELD" },
- { ARM64_INS_WFE, "WFE" },
- { ARM64_INS_WFI, "WFI" },
- { ARM64_INS_SEV, "SEV" },
- { ARM64_INS_SEVL, "SEVL" },
- { ARM64_INS_NGC, "NGC" },
- { ARM64_INS_NEG, "NEG" },
-
- // FIXME: map these with flag updated
- { ARM64_INS_NEG, "NEGS" },
- { ARM64_INS_NGC, "NGCS" },
- };
-
// NOTE: skip first NULL name in insn_name_maps
int i = name2id(&insn_name_maps[1], ARR_SIZE(insn_name_maps) - 1, name);
if (i == -1)
// try again with 'special' insn that is not available in insn_name_maps
- i = name2id(insn_name_maps2, ARR_SIZE(insn_name_maps2), name);
+ i = name2id(alias_insn_name_maps, ARR_SIZE(alias_insn_name_maps), name);
return (i != -1)? i : ARM64_REG_INVALID;
}