diff options
Diffstat (limited to 'disassembler')
| -rw-r--r-- | disassembler/disassembler_arm.cc | 69 | ||||
| -rw-r--r-- | disassembler/disassembler_x86.cc | 38 |
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); |