diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/arm/disassembler/arm_disasm.cpp | 141 | ||||
-rw-r--r-- | src/core/arm/disassembler/arm_disasm.h | 18 |
2 files changed, 153 insertions, 6 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index f6d44d85a..8eec64d48 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -4,6 +4,7 @@ #include "common/string_util.h" #include "core/arm/disassembler/arm_disasm.h" +#include "core/arm/skyeye_common/armsupp.h" static const char *cond_names[] = { "eq", @@ -37,6 +38,7 @@ static const char *opcode_names[] = { "blx", "bx", "cdp", + "clrex", "clz", "cmn", "cmp", @@ -46,6 +48,10 @@ static const char *opcode_names[] = { "ldr", "ldrb", "ldrbt", + "ldrex", + "ldrexb", + "ldrexd", + "ldrexh", "ldrh", "ldrsb", "ldrsh", @@ -58,11 +64,13 @@ static const char *opcode_names[] = { "msr", "mul", "mvn", + "nop", "orr", "pld", "rsb", "rsc", "sbc", + "sev", "smlal", "smull", "stc", @@ -70,6 +78,10 @@ static const char *opcode_names[] = { "str", "strb", "strbt", + "strex", + "strexb", + "strexd", + "strexh", "strh", "strt", "sub", @@ -80,6 +92,9 @@ static const char *opcode_names[] = { "tst", "umlal", "umull", + "wfe", + "wfi", + "yield", "undefined", "adc", @@ -172,6 +187,8 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassembleBX(insn); case OP_CDP: return "cdp"; + case OP_CLREX: + return "clrex"; case OP_CLZ: return DisassembleCLZ(insn); case OP_LDC: @@ -188,6 +205,15 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) case OP_STRBT: case OP_STRT: return DisassembleMem(insn); + case OP_LDREX: + case OP_LDREXB: + case OP_LDREXD: + case OP_LDREXH: + case OP_STREX: + case OP_STREXB: + case OP_STREXD: + case OP_STREXH: + return DisassembleREX(opcode, insn); case OP_LDRH: case OP_LDRSB: case OP_LDRSH: @@ -204,6 +230,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) return DisassembleMSR(insn); case OP_MUL: return DisassembleMUL(opcode, insn); + case OP_NOP: + case OP_SEV: + case OP_WFE: + case OP_WFI: + case OP_YIELD: + return DisassembleNoOperands(opcode, insn); case OP_PLD: return DisassemblePLD(insn); case OP_STC: @@ -646,6 +678,12 @@ std::string ARM_Disasm::DisassembleMSR(uint32_t insn) cond_to_str(cond), pd ? "spsr" : "cpsr", flags, rm); } +std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); +} + std::string ARM_Disasm::DisassemblePLD(uint32_t insn) { uint8_t is_reg = (insn >> 25) & 0x1; @@ -669,6 +707,36 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) } } +std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rt = BITS(insn, 0, 3); + uint32_t cond = BITS(insn, 28, 31); + + switch (opcode) { + case OP_STREX: + case OP_STREXB: + case OP_STREXH: + return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], + cond_to_str(cond), rd, rt, rn); + case OP_STREXD: + return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode], + cond_to_str(cond), rd, rt, rt + 1, rn); + + // for LDREX instructions, rd corresponds to Rt from reference manual + case OP_LDREX: + case OP_LDREXB: + case OP_LDREXH: + return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode], + cond_to_str(cond), rd, rn); + case OP_LDREXD: + return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], + cond_to_str(cond), rd, rd + 1, rn); + default: + return opcode_names[OP_UNDEFINED]; + } +} + std::string ARM_Disasm::DisassembleSWI(uint32_t insn) { uint8_t cond = (insn >> 28) & 0xf; @@ -721,12 +789,9 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) { } uint32_t bits7_4 = (insn >> 4) & 0xf; if (bits7_4 == 0x9) { - if ((insn & 0x0ff00ff0) == 0x01000090) { - // Swp instruction - uint8_t bit22 = (insn >> 22) & 0x1; - if (bit22) - return OP_SWPB; - return OP_SWP; + uint32_t bit24 = BIT(insn, 24); + if (bit24) { + return DecodeSyncPrimitive(insn); } // One of the multiply instructions return DecodeMUL(insn); @@ -739,6 +804,12 @@ Opcode ARM_Disasm::Decode00(uint32_t insn) { } } + uint32_t op1 = BITS(insn, 20, 24); + if (bit25 && (op1 == 0x12 || op1 == 0x16)) { + // One of the MSR (immediate) and hints instructions + return DecodeMSRImmAndHints(insn); + } + // One of the data processing instructions return DecodeALU(insn); } @@ -754,6 +825,10 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { // Pre-load return OP_PLD; } + if (insn == 0xf57ff01f) { + // Clear-Exclusive + return OP_CLREX; + } if (is_load) { if (is_byte) { // Load byte @@ -844,6 +919,35 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) { return OP_MCR; } +Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { + uint32_t op = BITS(insn, 20, 23); + uint32_t bit22 = BIT(insn, 22); + switch (op) { + case 0x0: + if (bit22) + return OP_SWPB; + return OP_SWP; + case 0x8: + return OP_STREX; + case 0x9: + return OP_LDREX; + case 0xA: + return OP_STREXD; + case 0xB: + return OP_LDREXD; + case 0xC: + return OP_STREXB; + case 0xD: + return OP_LDREXB; + case 0xE: + return OP_STREXH; + case 0xF: + return OP_LDREXH; + default: + return OP_UNDEFINED; + } +} + Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { uint8_t bit24 = (insn >> 24) & 0x1; if (bit24 != 0) { @@ -878,6 +982,31 @@ Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { return OP_SMLAL; } +Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { + uint32_t op = BIT(insn, 22); + uint32_t op1 = BITS(insn, 16, 19); + uint32_t op2 = BITS(insn, 0, 7); + + if (op == 0 && op1 == 0) { + switch (op2) { + case 0x0: + return OP_NOP; + case 0x1: + return OP_YIELD; + case 0x2: + return OP_WFE; + case 0x3: + return OP_WFI; + case 0x4: + return OP_SEV; + default: + return OP_UNDEFINED; + } + } + + return OP_MSR; +} + Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { uint8_t is_load = (insn >> 20) & 0x1; uint8_t bits_65 = (insn >> 5) & 0x3; diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h index f94bd4669..d04fd21eb 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -20,6 +20,7 @@ enum Opcode { OP_BLX, OP_BX, OP_CDP, + OP_CLREX, OP_CLZ, OP_CMN, OP_CMP, @@ -29,6 +30,10 @@ enum Opcode { OP_LDR, OP_LDRB, OP_LDRBT, + OP_LDREX, + OP_LDREXB, + OP_LDREXD, + OP_LDREXH, OP_LDRH, OP_LDRSB, OP_LDRSH, @@ -41,11 +46,13 @@ enum Opcode { OP_MSR, OP_MUL, OP_MVN, + OP_NOP, OP_ORR, OP_PLD, OP_RSB, OP_RSC, OP_SBC, + OP_SEV, OP_SMLAL, OP_SMULL, OP_STC, @@ -53,6 +60,10 @@ enum Opcode { OP_STR, OP_STRB, OP_STRBT, + OP_STREX, + OP_STREXB, + OP_STREXD, + OP_STREXH, OP_STRH, OP_STRT, OP_SUB, @@ -63,6 +74,9 @@ enum Opcode { OP_TST, OP_UMLAL, OP_UMULL, + OP_WFE, + OP_WFI, + OP_YIELD, // Define thumb opcodes OP_THUMB_UNDEFINED, @@ -117,7 +131,9 @@ class ARM_Disasm { static Opcode Decode01(uint32_t insn); static Opcode Decode10(uint32_t insn); static Opcode Decode11(uint32_t insn); + static Opcode DecodeSyncPrimitive(uint32_t insn); static Opcode DecodeMUL(uint32_t insn); + static Opcode DecodeMSRImmAndHints(uint32_t insn); static Opcode DecodeLDRH(uint32_t insn); static Opcode DecodeALU(uint32_t insn); @@ -135,7 +151,9 @@ class ARM_Disasm { static std::string DisassembleMUL(Opcode opcode, uint32_t insn); static std::string DisassembleMRS(uint32_t insn); static std::string DisassembleMSR(uint32_t insn); + static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); static std::string DisassemblePLD(uint32_t insn); + static std::string DisassembleREX(Opcode opcode, uint32_t insn); static std::string DisassembleSWI(uint32_t insn); static std::string DisassembleSWP(Opcode opcode, uint32_t insn); }; |