From 6b7abe3c817e9c12eace482693d0b805d172ce04 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Nov 2013 00:54:24 +0800 Subject: [PATCH] arm64: handle alias insn in a better way, and add support for MNEG. bug reported by Patroklos Argyroudis --- MCInst.c | 10 ++++++++++ MCInst.h | 5 +++++ arch/AArch64/AArch64InstPrinter.c | 5 +++-- arch/AArch64/mapping.c | 4 ++++ arch/AArch64/mapping.h | 2 +- cs.c | 8 ++++++-- include/arm64.h | 4 ++++ tests/test_arm64.c | 2 ++ 8 files changed, 35 insertions(+), 5 deletions(-) diff --git a/MCInst.c b/MCInst.c index 1ec8f8a9..c7d8b176 100644 --- a/MCInst.c +++ b/MCInst.c @@ -35,11 +35,21 @@ void MCInst_setOpcode(MCInst *inst, unsigned Op) inst->Opcode = Op; } +void MCInst_setOpcodePub(MCInst *inst, unsigned Op) +{ + inst->OpcodePub = Op; +} + unsigned MCInst_getOpcode(const MCInst *inst) { return inst->Opcode; } +unsigned MCInst_getOpcodePub(const MCInst *inst) +{ + return inst->OpcodePub; +} + MCOperand *MCInst_getOperand(MCInst *inst, unsigned i) { return &inst->Operands[i]; diff --git a/MCInst.h b/MCInst.h index be7c221d..2407eff2 100644 --- a/MCInst.h +++ b/MCInst.h @@ -89,6 +89,7 @@ struct MCInst { unsigned size; // number of operands cs_insn pub_insn; // insn to be exposed to public cs_mode mode; // to be referenced by internal code + unsigned OpcodePub; }; void MCInst_Init(MCInst *inst); @@ -101,6 +102,10 @@ void MCInst_setOpcode(MCInst *inst, unsigned Op); unsigned MCInst_getOpcode(const MCInst*); +void MCInst_setOpcodePub(MCInst *inst, unsigned Op); + +unsigned MCInst_getOpcodePub(const MCInst*); + MCOperand *MCInst_getOperand(MCInst *inst, unsigned i); unsigned MCInst_getNumOperands(const MCInst *inst); diff --git a/arch/AArch64/AArch64InstPrinter.c b/arch/AArch64/AArch64InstPrinter.c index 1cfddfcc..d4b208b1 100644 --- a/arch/AArch64/AArch64InstPrinter.c +++ b/arch/AArch64/AArch64InstPrinter.c @@ -636,10 +636,11 @@ void AArch64_printInst(MCInst *MI, SStream *O, void *Info) if (printAliasInstr(MI, O, Info)) { char *mnem = strdup(O->buffer); char *tab = strchr(mnem, '\t'); - if (tab) + if (tab) { *tab = '\0'; + } // reflect the new insn name (alias) in the opcode - MCInst_setOpcode(MI, AArch64_get_insn_id2(AArch64_map_insn(mnem))); + MCInst_setOpcodePub(MI, AArch64_map_insn(mnem)); free(mnem); } else AArch64InstPrinter_printInstruction(MI, O); diff --git a/arch/AArch64/mapping.c b/arch/AArch64/mapping.c index 73549010..b8aed36a 100644 --- a/arch/AArch64/mapping.c +++ b/arch/AArch64/mapping.c @@ -1854,6 +1854,7 @@ void AArch64_get_insn_id(cs_insn *insn, unsigned int id) } } +// 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); @@ -2224,6 +2225,7 @@ char *AArch64_insn_name(unsigned int id) 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 @@ -2234,6 +2236,8 @@ arm64_reg AArch64_map_insn(char *name) { ARM64_INS_BIC, "BICS" }, { ARM64_INS_SBC, "SBCS" }, { ARM64_INS_SUB, "SUBS" }, + // alias insn + { ARM64_INS_MNEG, "MNEG" }, }; // NOTE: skip first NULL name in insn_name_maps diff --git a/arch/AArch64/mapping.h b/arch/AArch64/mapping.h index 7cd316b9..5e0f3141 100644 --- a/arch/AArch64/mapping.h +++ b/arch/AArch64/mapping.h @@ -18,7 +18,7 @@ unsigned int AArch64_get_insn_id2(unsigned int id); char *AArch64_insn_name(unsigned int id); -// map instruction name to instruction ID +// map instruction name to public instruction ID arm64_reg AArch64_map_insn(char *name); #endif diff --git a/cs.c b/cs.c index 100cf882..0147533b 100644 --- a/cs.c +++ b/cs.c @@ -170,8 +170,12 @@ static void fill_insn(cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mc memcpy(insn, &mci->pub_insn, sizeof(*insn)); // map internal instruction opcode to public insn ID - if (handle->insn_id) - handle->insn_id(insn, MCInst_getOpcode(mci)); + if (MCInst_getOpcodePub(mci)) + MCInst_setOpcode(mci, MCInst_getOpcodePub(mci)); + else { + if (handle->insn_id) + handle->insn_id(insn, MCInst_getOpcode(mci)); + } if (printer) printer(insn->id, insn, buffer); diff --git a/include/arm64.h b/include/arm64.h index 9f721173..b329df04 100644 --- a/include/arm64.h +++ b/include/arm64.h @@ -691,6 +691,10 @@ typedef enum arm64_insn { ARM64_INS_USUBW, ARM64_INS_UXTB, ARM64_INS_UXTH, + + // alias insn + ARM64_INS_MNEG, + ARM64_INS_MAX, } arm64_insn; diff --git a/tests/test_arm64.c b/tests/test_arm64.c index 29e4ad75..993df04c 100644 --- a/tests/test_arm64.c +++ b/tests/test_arm64.c @@ -131,6 +131,8 @@ static void test() //#define ARM64_CODE "\x5f\x3f\x03\xd5" // clrex //#define ARM64_CODE "\x5f\x3e\x03\xd5" // clrex #14 //#define ARM64_CODE "\x20\x00\x02\xab" // adds x0, x1, x2 (alias of adds x0, x1, x2, lsl #0) +//#define ARM64_CODE "\x20\xf4\x18\x9e" // fcvtzs x0, s1, #3 +//#define ARM64_CODE "\x20\xfc\x02\x9b" // mneg x0, x1, x2 #define ARM64_CODE "\x21\x7c\x02\x9b\x21\x7c\x00\x53\x00\x40\x21\x4b\xe1\x0b\x40\xb9\x20\x04\x81\xda\x20\x08\x02\x8b" struct platform platforms[] = {