summaryrefslogtreecommitdiff
path: root/disassembler
diff options
context:
space:
mode:
Diffstat (limited to 'disassembler')
-rw-r--r--disassembler/disassembler_arm.cc69
-rw-r--r--disassembler/disassembler_x86.cc38
2 files changed, 86 insertions, 21 deletions
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 4e4a512713..1f565e504a 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -269,18 +269,34 @@ void DisassemblerArm::DumpArm(std::ostream& os, const uint8_t* instr_ptr) {
uint32_t op = (instruction >> 21) & 0xf;
opcode = kDataProcessingOperations[op];
bool implicit_s = ((op & ~3) == 8); // TST, TEQ, CMP, and CMN.
- if (implicit_s) {
- // Rd is unused (and not shown), and we don't show the 's' suffix either.
- } else {
+ bool is_mov = op == 0b1101 || op == 0b1111;
+ if (is_mov) {
+ // Show only Rd and Rm.
if (s) {
- suffixes += 's';
- }
- args << ArmRegister(instruction, 12) << ", ";
- }
- if (i) {
- args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
+ suffixes += 's';
+ }
+ args << ArmRegister(instruction, 12) << ", ";
+ if (i) {
+ args << ShiftedImmediate(instruction);
+ } else {
+ // TODO: Shifted register.
+ args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
+ }
} else {
- args << Rm(instruction);
+ if (implicit_s) {
+ // Rd is unused (and not shown), and we don't show the 's' suffix either.
+ } else {
+ if (s) {
+ suffixes += 's';
+ }
+ args << ArmRegister(instruction, 12) << ", ";
+ }
+ if (i) {
+ args << ArmRegister(instruction, 16) << ", " << ShiftedImmediate(instruction);
+ } else {
+ // TODO: Shifted register.
+ args << ArmRegister(instruction, 16) << ", " << ArmRegister(instruction, 0);
+ }
}
}
break;
@@ -1291,7 +1307,7 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
int32_t imm32 = (imm8 << 24) >> 24; // sign-extend imm8
if (Rn.r == 13 && P == 1 && U == 0 && W == 1 && imm32 == 4) {
opcode << "push";
- args << Rt;
+ args << "{" << Rt << "}";
} else if (Rn.r == 15 || (P == 0 && W == 0)) {
opcode << "UNDEFINED";
} else {
@@ -1443,10 +1459,33 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr)
}
args << "]";
} else {
- // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
- uint32_t imm8 = instr & 0xFF;
- opcode << "ldrt";
- args << Rt << ", [" << Rn << ", #" << imm8 << "]";
+ bool p = (instr & (1 << 10)) != 0;
+ bool w = (instr & (1 << 8)) != 0;
+ bool u = (instr & (1 << 9)) != 0;
+ if (p && u && !w) {
+ // LDRT Rt, [Rn, #imm8] - 111 11 00 00 101 nnnn tttt 1110iiiiiiii
+ uint32_t imm8 = instr & 0xFF;
+ opcode << "ldrt";
+ args << Rt << ", [" << Rn << ", #" << imm8 << "]";
+ } else if (Rn.r == 13 && !p && u && w && (instr & 0xff) == 4) {
+ // POP
+ opcode << "pop";
+ args << "{" << Rt << "}";
+ } else {
+ bool wback = !p || w;
+ uint32_t offset = (instr & 0xff);
+ opcode << "ldr.w";
+ args << Rt << ",";
+ if (p && !wback) {
+ args << "[" << Rn << ", #" << offset << "]";
+ } else if (p && wback) {
+ args << "[" << Rn << ", #" << offset << "]!";
+ } else if (!p && wback) {
+ args << "[" << Rn << "], #" << offset;
+ } else {
+ LOG(FATAL) << p << " " << w;
+ }
+ }
}
break;
}
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index e6a6860626..b012bc1cc1 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -56,10 +56,16 @@ static const char* gReg64Names[] = {
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};
+// 64-bit opcode REX modifier.
+constexpr uint8_t REX_W = 0b1000;
+constexpr uint8_t REX_R = 0b0100;
+constexpr uint8_t REX_X = 0b0010;
+constexpr uint8_t REX_B = 0b0001;
+
static void DumpReg0(std::ostream& os, uint8_t rex, size_t reg,
bool byte_operand, uint8_t size_override) {
DCHECK_LT(reg, (rex == 0) ? 8u : 16u);
- bool rex_w = (rex & 0b1000) != 0;
+ bool rex_w = (rex & REX_W) != 0;
if (byte_operand) {
os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]);
} else if (rex_w) {
@@ -86,14 +92,14 @@ static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg,
static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
bool byte_operand, uint8_t size_override, RegFile reg_file) {
- bool rex_r = (rex & 0b0100) != 0;
+ bool rex_r = (rex & REX_R) != 0;
size_t reg_num = rex_r ? (reg + 8) : reg;
DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
}
static void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg,
bool byte_operand, uint8_t size_override, RegFile reg_file) {
- bool rex_b = (rex & 0b0001) != 0;
+ bool rex_b = (rex & REX_B) != 0;
size_t reg_num = rex_b ? (reg + 8) : reg;
DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
}
@@ -107,19 +113,19 @@ static void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) {
}
static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
- bool rex_b = (rex & 0b0001) != 0;
+ bool rex_b = (rex & REX_B) != 0;
size_t reg_num = rex_b ? (reg + 8) : reg;
DumpAddrReg(os, rex, reg_num);
}
static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) {
- bool rex_x = (rex & 0b0010) != 0;
+ bool rex_x = (rex & REX_X) != 0;
uint8_t reg_num = rex_x ? (reg + 8) : reg;
DumpAddrReg(os, rex, reg_num);
}
static void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg) {
- bool rex_b = (rex & 0b0001) != 0;
+ bool rex_b = (rex & REX_B) != 0;
size_t reg_num = rex_b ? (reg + 8) : reg;
DumpReg0(os, rex, reg_num, false, 0);
}
@@ -896,6 +902,7 @@ DISASSEMBLER_ENTRY(cmp,
case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
opcode << "mov";
immediate_bytes = 1;
+ byte_operand = true;
reg_in_opcode = true;
break;
case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
@@ -916,6 +923,15 @@ DISASSEMBLER_ENTRY(cmp,
byte_operand = (*instr == 0xC0);
break;
case 0xC3: opcode << "ret"; break;
+ case 0xC6:
+ static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6"};
+ modrm_opcodes = c6_opcodes;
+ store = true;
+ immediate_bytes = 1;
+ has_modrm = true;
+ reg_is_opcode = true;
+ byte_operand = true;
+ break;
case 0xC7:
static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"};
modrm_opcodes = c7_opcodes;
@@ -1064,6 +1080,16 @@ DISASSEMBLER_ENTRY(cmp,
if (reg_is_opcode && modrm_opcodes != NULL) {
opcode << modrm_opcodes[reg_or_opcode];
}
+
+ // Add opcode suffixes to indicate size.
+ if (byte_operand) {
+ opcode << 'b';
+ } else if ((rex & REX_W) != 0) {
+ opcode << 'q';
+ } else if (prefix[2] == 0x66) {
+ opcode << 'w';
+ }
+
if (load) {
if (!reg_is_opcode) {
DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);