diff options
Diffstat (limited to 'src/core/arm')
-rw-r--r-- | src/core/arm/disassembler/arm_disasm.cpp | 467 | ||||
-rw-r--r-- | src/core/arm/disassembler/arm_disasm.h | 79 |
2 files changed, 545 insertions, 1 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp index 964e30112..1d40ae030 100644 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ b/src/core/arm/disassembler/arm_disasm.cpp @@ -1,6 +1,7 @@ // Copyright 2006 The Android Open Source Project #include <string> +#include <unordered_set> #include "common/string_util.h" #include "core/arm/disassembler/arm_disasm.h" @@ -66,13 +67,47 @@ static const char *opcode_names[] = { "mvn", "nop", "orr", + "pkh", "pld", + "qadd16", + "qadd8", + "qasx", + "qsax", + "qsub16", + "qsub8", + "rev", + "rev16", + "revsh", "rsb", "rsc", + "sadd16", + "sadd8", + "sasx", "sbc", + "sel", "sev", + "shadd16", + "shadd8", + "shasx", + "shsax", + "shsub16", + "shsub8", + "smlad", "smlal", + "smlald", + "smlsd", + "smlsld", + "smmla", + "smmls", + "smmul", + "smuad", "smull", + "smusd", + "ssat", + "ssat16", + "ssax", + "ssub16", + "ssub8", "stc", "stm", "str", @@ -88,10 +123,44 @@ static const char *opcode_names[] = { "swi", "swp", "swpb", + "sxtab", + "sxtab16", + "sxtah", + "sxtb", + "sxtb16", + "sxth", "teq", "tst", + "uadd16", + "uadd8", + "uasx", + "uhadd16", + "uhadd8", + "uhasx", + "uhsax", + "uhsub16", + "uhsub8", "umlal", "umull", + "uqadd16", + "uqadd8", + "uqasx", + "uqsax", + "uqsub16", + "uqsub8", + "usad8", + "usada8", + "usat", + "usat16", + "usax", + "usub16", + "usub8", + "uxtab", + "uxtab16", + "uxtah", + "uxtb", + "uxtb16", + "uxth", "wfe", "wfi", "yield", @@ -236,8 +305,70 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) case OP_WFI: case OP_YIELD: return DisassembleNoOperands(opcode, insn); + case OP_PKH: + return DisassemblePKH(insn); case OP_PLD: return DisassemblePLD(insn); + case OP_QADD16: + case OP_QADD8: + case OP_QASX: + case OP_QSAX: + case OP_QSUB16: + case OP_QSUB8: + case OP_SADD16: + case OP_SADD8: + case OP_SASX: + case OP_SHADD16: + case OP_SHADD8: + case OP_SHASX: + case OP_SHSAX: + case OP_SHSUB16: + case OP_SHSUB8: + case OP_SSAX: + case OP_SSUB16: + case OP_SSUB8: + case OP_UADD16: + case OP_UADD8: + case OP_UASX: + case OP_UHADD16: + case OP_UHADD8: + case OP_UHASX: + case OP_UHSAX: + case OP_UHSUB16: + case OP_UHSUB8: + case OP_UQADD16: + case OP_UQADD8: + case OP_UQASX: + case OP_UQSAX: + case OP_UQSUB16: + case OP_UQSUB8: + case OP_USAX: + case OP_USUB16: + case OP_USUB8: + return DisassembleParallelAddSub(opcode, insn); + case OP_REV: + case OP_REV16: + case OP_REVSH: + return DisassembleREV(opcode, insn); + case OP_SEL: + return DisassembleSEL(insn); + case OP_SMLAD: + case OP_SMLALD: + case OP_SMLSD: + case OP_SMLSLD: + case OP_SMMLA: + case OP_SMMLS: + case OP_SMMUL: + case OP_SMUAD: + case OP_SMUSD: + case OP_USAD8: + case OP_USADA8: + return DisassembleMediaMulDiv(opcode, insn); + case OP_SSAT: + case OP_SSAT16: + case OP_USAT: + case OP_USAT16: + return DisassembleSAT(opcode, insn); case OP_STC: return "stc"; case OP_SWI: @@ -245,6 +376,19 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) case OP_SWP: case OP_SWPB: return DisassembleSWP(opcode, insn); + case OP_SXTAB: + case OP_SXTAB16: + case OP_SXTAH: + case OP_SXTB: + case OP_SXTB16: + case OP_SXTH: + case OP_UXTAB: + case OP_UXTAB16: + case OP_UXTAH: + case OP_UXTB: + case OP_UXTB16: + case OP_UXTH: + return DisassembleXT(opcode, insn); case OP_UMLAL: case OP_UMULL: case OP_SMLAL: @@ -382,6 +526,38 @@ std::string ARM_Disasm::DisassembleCLZ(uint32_t insn) return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); } +std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rd = BITS(insn, 16, 19); + uint32_t ra = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 8, 11); + uint32_t m = BIT(insn, 5); + uint32_t rn = BITS(insn, 0, 3); + + std::string cross = ""; + if (m) { + if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS) + cross = "r"; + else + cross = "x"; + } + + std::string ext_reg = ""; + std::unordered_set<Opcode, std::hash<int>> with_ext_reg = { + OP_SMLAD, OP_SMLSD, OP_SMMLA, OP_SMMLS, OP_USADA8 + }; + if (with_ext_reg.find(opcode) != with_ext_reg.end()) + ext_reg = Common::StringFromFormat(", r%u", ra); + + std::string rd_low = ""; + if (opcode == OP_SMLALD || opcode == OP_SMLSLD) + rd_low = Common::StringFromFormat("r%u, ", ra); + + return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode], + cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm, + ext_reg.c_str()); +} + std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, uint32_t insn) { std::string tmp_list; @@ -684,6 +860,40 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); } +std::string ARM_Disasm::DisassembleParallelAddSub(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[opcode], cond_to_str(cond), + rd, rn, rm); +} + +std::string ARM_Disasm::DisassemblePKH(uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t imm5 = BITS(insn, 7, 11); + uint32_t tb = BIT(insn, 6); + uint32_t rm = BITS(insn, 0, 3); + + std::string suffix = tb ? "tb" : "bt"; + std::string shift = ""; + + if (tb && imm5 == 0) + imm5 = 32; + + if (imm5 > 0) { + shift = tb ? ", ASR" : ", LSL"; + shift += " #" + std::to_string(imm5); + } + + return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), + rd, rn, rm, shift.c_str()); +} + std::string ARM_Disasm::DisassemblePLD(uint32_t insn) { uint8_t is_reg = (insn >> 25) & 0x1; @@ -707,6 +917,15 @@ std::string ARM_Disasm::DisassemblePLD(uint32_t insn) } } +std::string ARM_Disasm::DisassembleREV(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u", opcode_names[opcode], cond_to_str(cond), + rd, rm); +} + std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { uint32_t rn = BITS(insn, 16, 19); uint32_t rd = BITS(insn, 12, 15); @@ -737,6 +956,44 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { } } +std::string ARM_Disasm::DisassembleSAT(Opcode opcode, uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t sat_imm = BITS(insn, 16, 20); + uint32_t rd = BITS(insn, 12, 15); + uint32_t imm5 = BITS(insn, 7, 11); + uint32_t sh = BIT(insn, 6); + uint32_t rn = BITS(insn, 0, 3); + + std::string shift_part = ""; + bool opcode_has_shift = (opcode == OP_SSAT) || (opcode == OP_USAT); + if (opcode_has_shift && !(sh == 0 && imm5 == 0)) { + if (sh == 0) + shift_part += ", LSL #"; + else + shift_part += ", ASR #"; + + if (imm5 == 0) + imm5 = 32; + shift_part += std::to_string(imm5); + } + + if (opcode == OP_SSAT || opcode == OP_SSAT16) + sat_imm++; + + return Common::StringFromFormat("%s%s\tr%u, #%u, r%u%s", opcode_names[opcode], cond_to_str(cond), rd, + sat_imm, rn, shift_part.c_str()); +} + +std::string ARM_Disasm::DisassembleSEL(uint32_t insn) { + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rm = BITS(insn, 0, 3); + + return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), + rd, rn, rm); +} + std::string ARM_Disasm::DisassembleSWI(uint32_t insn) { uint8_t cond = (insn >> 28) & 0xf; @@ -756,6 +1013,30 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); } +std::string ARM_Disasm::DisassembleXT(Opcode opcode, uint32_t insn) +{ + uint32_t cond = BITS(insn, 28, 31); + uint32_t rn = BITS(insn, 16, 19); + uint32_t rd = BITS(insn, 12, 15); + uint32_t rotate = BITS(insn, 10, 11); + uint32_t rm = BITS(insn, 0, 3); + + std::string rn_part = ""; + static std::unordered_set<Opcode, std::hash<int>> extend_with_add = { + OP_SXTAB, OP_SXTAB16, OP_SXTAH, + OP_UXTAB, OP_UXTAB16, OP_UXTAH + }; + if (extend_with_add.find(opcode) != extend_with_add.end()) + rn_part = ", r" + std::to_string(rn); + + std::string rotate_part = ""; + if (rotate != 0) + rotate_part = ", ROR #" + std::to_string(rotate << 3); + + return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), + rd, rn_part.c_str(), rm, rotate_part.c_str()); +} + Opcode ARM_Disasm::Decode(uint32_t insn) { uint32_t bits27_26 = (insn >> 26) & 0x3; switch (bits27_26) { @@ -818,7 +1099,7 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { uint8_t is_reg = (insn >> 25) & 0x1; uint8_t bit4 = (insn >> 4) & 0x1; if (is_reg == 1 && bit4 == 1) - return OP_UNDEFINED; + return DecodeMedia(insn); uint8_t is_load = (insn >> 20) & 0x1; uint8_t is_byte = (insn >> 22) & 0x1; if ((insn & 0xfd70f000) == 0xf550f000) { @@ -940,6 +1221,120 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { } } +Opcode ARM_Disasm::DecodeParallelAddSub(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 21); + uint32_t op2 = BITS(insn, 5, 7); + uint32_t is_unsigned = BIT(insn, 22); + + if (op1 == 0x0 || op2 == 0x5 || op2 == 0x6) + return OP_UNDEFINED; + + // change op1 range from [1, 3] to range [0, 2] + op1--; + + // change op2 range from [0, 4] U {7} to range [0, 5] + if (op2 == 0x7) + op2 = 0x5; + + static std::vector<Opcode> opcodes = { + // op1 = 0 + OP_SADD16, OP_UADD16, + OP_SASX, OP_UASX, + OP_SSAX, OP_USAX, + OP_SSUB16, OP_USUB16, + OP_SADD8, OP_UADD8, + OP_SSUB8, OP_USUB8, + // op1 = 1 + OP_QADD16, OP_UQADD16, + OP_QASX, OP_UQASX, + OP_QSAX, OP_UQSAX, + OP_QSUB16, OP_UQSUB16, + OP_QADD8, OP_UQADD8, + OP_QSUB8, OP_UQSUB8, + // op1 = 2 + OP_SHADD16, OP_UHADD16, + OP_SHASX, OP_UHASX, + OP_SHSAX, OP_UHSAX, + OP_SHSUB16, OP_UHSUB16, + OP_SHADD8, OP_UHADD8, + OP_SHSUB8, OP_UHSUB8 + }; + + uint32_t opcode_index = op1 * 12 + op2 * 2 + is_unsigned; + return opcodes[opcode_index]; +} + +Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 22); + uint32_t a = BITS(insn, 16, 19); + uint32_t op2 = BITS(insn, 5, 7); + + switch (op1) { + case 0x0: + if (BIT(op2, 0) == 0) + return OP_PKH; + if (op2 == 0x3 && a != 0xf) + return OP_SXTAB16; + if (op2 == 0x3 && a == 0xf) + return OP_SXTB16; + if (op2 == 0x5) + return OP_SEL; + break; + case 0x2: + if (BIT(op2, 0) == 0) + return OP_SSAT; + if (op2 == 0x1) + return OP_SSAT16; + if (op2 == 0x3 && a != 0xf) + return OP_SXTAB; + if (op2 == 0x3 && a == 0xf) + return OP_SXTB; + break; + case 0x3: + if (op2 == 0x1) + return OP_REV; + if (BIT(op2, 0) == 0) + return OP_SSAT; + if (op2 == 0x3 && a != 0xf) + return OP_SXTAH; + if (op2 == 0x3 && a == 0xf) + return OP_SXTH; + if (op2 == 0x5) + return OP_REV16; + break; + case 0x4: + if (op2 == 0x3 && a != 0xf) + return OP_UXTAB16; + if (op2 == 0x3 && a == 0xf) + return OP_UXTB16; + break; + case 0x6: + if (BIT(op2, 0) == 0) + return OP_USAT; + if (op2 == 0x1) + return OP_USAT16; + if (op2 == 0x3 && a != 0xf) + return OP_UXTAB; + if (op2 == 0x3 && a == 0xf) + return OP_UXTB; + break; + case 0x7: + if (BIT(op2, 0) == 0) + return OP_USAT; + if (op2 == 0x3 && a != 0xf) + return OP_UXTAH; + if (op2 == 0x3 && a == 0xf) + return OP_UXTH; + if (op2 == 0x5) + return OP_REVSH; + break; + default: + break; + } + + return OP_UNDEFINED; +} + Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { uint8_t bit24 = (insn >> 24) & 0x1; if (bit24 != 0) { @@ -999,6 +1394,76 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { return OP_MSR; } +Opcode ARM_Disasm::DecodeMediaMulDiv(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 22); + uint32_t op2_h = BITS(insn, 6, 7); + uint32_t a = BITS(insn, 12, 15); + + switch (op1) { + case 0x0: + if (op2_h == 0x0) { + if (a != 0xf) + return OP_SMLAD; + else + return OP_SMUAD; + } else if (op2_h == 0x1) { + if (a != 0xf) + return OP_SMLSD; + else + return OP_SMUSD; + } + break; + case 0x4: + if (op2_h == 0x0) + return OP_SMLALD; + else if (op2_h == 0x1) + return OP_SMLSLD; + break; + case 0x5: + if (op2_h == 0x0) { + if (a != 0xf) + return OP_SMMLA; + else + return OP_SMMUL; + } else if (op2_h == 0x3) { + return OP_SMMLS; + } + break; + default: + break; + } + + return OP_UNDEFINED; +} + +Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { + uint32_t op1 = BITS(insn, 20, 24); + uint32_t rd = BITS(insn, 12, 15); + uint32_t op2 = BITS(insn, 5, 7); + + switch (BITS(op1, 3, 4)) { + case 0x0: + // unsigned and signed parallel addition and subtraction + return DecodeParallelAddSub(insn); + case 0x1: + // Packing, unpacking, saturation, and reversal + return DecodePackingSaturationReversal(insn); + case 0x2: + // Signed multiply, signed and unsigned divide + return DecodeMediaMulDiv(insn); + case 0x3: + if (op2 == 0 && rd == 0xf) + return OP_USAD8; + if (op2 == 0 && rd != 0xf) + return OP_USADA8; + break; + default: + break; + } + + return OP_UNDEFINED; +} + 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 d04fd21eb..259a77861 100644 --- a/src/core/arm/disassembler/arm_disasm.h +++ b/src/core/arm/disassembler/arm_disasm.h @@ -48,13 +48,47 @@ enum Opcode { OP_MVN, OP_NOP, OP_ORR, + OP_PKH, OP_PLD, + OP_QADD16, + OP_QADD8, + OP_QASX, + OP_QSAX, + OP_QSUB16, + OP_QSUB8, + OP_REV, + OP_REV16, + OP_REVSH, OP_RSB, OP_RSC, + OP_SADD16, + OP_SADD8, + OP_SASX, OP_SBC, + OP_SEL, OP_SEV, + OP_SHADD16, + OP_SHADD8, + OP_SHASX, + OP_SHSAX, + OP_SHSUB16, + OP_SHSUB8, + OP_SMLAD, OP_SMLAL, + OP_SMLALD, + OP_SMLSD, + OP_SMLSLD, + OP_SMMLA, + OP_SMMLS, + OP_SMMUL, + OP_SMUAD, OP_SMULL, + OP_SMUSD, + OP_SSAT, + OP_SSAT16, + OP_SSAX, + OP_SSUB16, + OP_SSUB8, OP_STC, OP_STM, OP_STR, @@ -70,10 +104,44 @@ enum Opcode { OP_SWI, OP_SWP, OP_SWPB, + OP_SXTAB, + OP_SXTAB16, + OP_SXTAH, + OP_SXTB, + OP_SXTB16, + OP_SXTH, OP_TEQ, OP_TST, + OP_UADD16, + OP_UADD8, + OP_UASX, + OP_UHADD16, + OP_UHADD8, + OP_UHASX, + OP_UHSAX, + OP_UHSUB16, + OP_UHSUB8, OP_UMLAL, OP_UMULL, + OP_UQADD16, + OP_UQADD8, + OP_UQASX, + OP_UQSAX, + OP_UQSUB16, + OP_UQSUB8, + OP_USAD8, + OP_USADA8, + OP_USAT, + OP_USAT16, + OP_USAX, + OP_USUB16, + OP_USUB8, + OP_UXTAB, + OP_UXTAB16, + OP_UXTAH, + OP_UXTB, + OP_UXTB16, + OP_UXTH, OP_WFE, OP_WFI, OP_YIELD, @@ -132,8 +200,12 @@ class ARM_Disasm { static Opcode Decode10(uint32_t insn); static Opcode Decode11(uint32_t insn); static Opcode DecodeSyncPrimitive(uint32_t insn); + static Opcode DecodeParallelAddSub(uint32_t insn); + static Opcode DecodePackingSaturationReversal(uint32_t insn); static Opcode DecodeMUL(uint32_t insn); static Opcode DecodeMSRImmAndHints(uint32_t insn); + static Opcode DecodeMediaMulDiv(uint32_t insn); + static Opcode DecodeMedia(uint32_t insn); static Opcode DecodeLDRH(uint32_t insn); static Opcode DecodeALU(uint32_t insn); @@ -142,6 +214,7 @@ class ARM_Disasm { static std::string DisassembleBX(uint32_t insn); static std::string DisassembleBKPT(uint32_t insn); static std::string DisassembleCLZ(uint32_t insn); + static std::string DisassembleMediaMulDiv(Opcode opcode, uint32_t insn); static std::string DisassembleMemblock(Opcode opcode, uint32_t insn); static std::string DisassembleMem(uint32_t insn); static std::string DisassembleMemHalf(uint32_t insn); @@ -152,8 +225,14 @@ class ARM_Disasm { 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 DisassembleParallelAddSub(Opcode opcode, uint32_t insn); + static std::string DisassemblePKH(uint32_t insn); static std::string DisassemblePLD(uint32_t insn); + static std::string DisassembleREV(Opcode opcode, uint32_t insn); static std::string DisassembleREX(Opcode opcode, uint32_t insn); + static std::string DisassembleSAT(Opcode opcode, uint32_t insn); + static std::string DisassembleSEL(uint32_t insn); static std::string DisassembleSWI(uint32_t insn); static std::string DisassembleSWP(Opcode opcode, uint32_t insn); + static std::string DisassembleXT(Opcode opcode, uint32_t insn); }; |