summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp163
-rw-r--r--src/core/arm/disassembler/arm_disasm.h19
2 files changed, 181 insertions, 1 deletions
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 964e30112..3ac867949 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,10 +67,12 @@ static const char *opcode_names[] = {
"mvn",
"nop",
"orr",
+ "pkh",
"pld",
"rsb",
"rsc",
"sbc",
+ "sel",
"sev",
"smlal",
"smull",
@@ -88,10 +91,22 @@ static const char *opcode_names[] = {
"swi",
"swp",
"swpb",
+ "sxtab",
+ "sxtab16",
+ "sxtah",
+ "sxtb",
+ "sxtb16",
+ "sxth",
"teq",
"tst",
"umlal",
"umull",
+ "uxtab",
+ "uxtab16",
+ "uxtah",
+ "uxtb",
+ "uxtb16",
+ "uxth",
"wfe",
"wfi",
"yield",
@@ -236,8 +251,12 @@ 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_SEL:
+ return DisassembleSEL(insn);
case OP_STC:
return "stc";
case OP_SWI:
@@ -245,6 +264,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:
@@ -684,6 +716,30 @@ 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::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;
@@ -737,6 +793,17 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) {
}
}
+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 +823,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 +909,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 +1031,59 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) {
}
}
+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 (op2 == 0x3 && a != 0xf)
+ return OP_SXTAB;
+ if (op2 == 0x3 && a == 0xf)
+ return OP_SXTB;
+ break;
+ case 0x3:
+ if (op2 == 0x3 && a != 0xf)
+ return OP_SXTAH;
+ if (op2 == 0x3 && a == 0xf)
+ return OP_SXTH;
+ break;
+ case 0x4:
+ if (op2 == 0x3 && a != 0xf)
+ return OP_UXTAB16;
+ if (op2 == 0x3 && a == 0xf)
+ return OP_UXTB16;
+ break;
+ case 0x6:
+ if (op2 == 0x3 && a != 0xf)
+ return OP_UXTAB;
+ if (op2 == 0x3 && a == 0xf)
+ return OP_UXTB;
+ break;
+ case 0x7:
+ if (op2 == 0x3 && a != 0xf)
+ return OP_UXTAH;
+ if (op2 == 0x3 && a == 0xf)
+ return OP_UXTH;
+ break;
+ default:
+ break;
+ }
+
+ return OP_UNDEFINED;
+}
+
Opcode ARM_Disasm::DecodeMUL(uint32_t insn) {
uint8_t bit24 = (insn >> 24) & 0x1;
if (bit24 != 0) {
@@ -999,6 +1143,23 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) {
return OP_MSR;
}
+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);
+ uint32_t rn = BITS(insn, 0, 3);
+
+ switch (BITS(op1, 3, 4)) {
+ case 0x1:
+ // Packing, unpacking, saturation, and reversal
+ return DecodePackingSaturationReversal(insn);
+ 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..20e92fd0e 100644
--- a/src/core/arm/disassembler/arm_disasm.h
+++ b/src/core/arm/disassembler/arm_disasm.h
@@ -48,10 +48,12 @@ enum Opcode {
OP_MVN,
OP_NOP,
OP_ORR,
+ OP_PKH,
OP_PLD,
OP_RSB,
OP_RSC,
OP_SBC,
+ OP_SEL,
OP_SEV,
OP_SMLAL,
OP_SMULL,
@@ -70,10 +72,22 @@ 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_UMLAL,
OP_UMULL,
+ OP_UXTAB,
+ OP_UXTAB16,
+ OP_UXTAH,
+ OP_UXTB,
+ OP_UXTB16,
+ OP_UXTH,
OP_WFE,
OP_WFI,
OP_YIELD,
@@ -132,8 +146,10 @@ class ARM_Disasm {
static Opcode Decode10(uint32_t insn);
static Opcode Decode11(uint32_t insn);
static Opcode DecodeSyncPrimitive(uint32_t insn);
+ static Opcode DecodePackingSaturationReversal(uint32_t insn);
static Opcode DecodeMUL(uint32_t insn);
static Opcode DecodeMSRImmAndHints(uint32_t insn);
+ static Opcode DecodeMedia(uint32_t insn);
static Opcode DecodeLDRH(uint32_t insn);
static Opcode DecodeALU(uint32_t insn);
@@ -152,8 +168,11 @@ 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 DisassemblePKH(uint32_t insn);
static std::string DisassemblePLD(uint32_t insn);
static std::string DisassembleREX(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);
};