summaryrefslogtreecommitdiff
path: root/disassembler/disassembler_x86.cc
diff options
context:
space:
mode:
Diffstat (limited to 'disassembler/disassembler_x86.cc')
-rw-r--r--disassembler/disassembler_x86.cc131
1 files changed, 123 insertions, 8 deletions
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 1f74c93045..e12bcec776 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -21,9 +21,10 @@
#include <ostream>
#include <sstream>
-#include "base/logging.h"
-#include "base/stringprintf.h"
-#include "thread.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
namespace art {
namespace x86 {
@@ -243,7 +244,38 @@ std::string DisassemblerX86::DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64,
return address.str();
}
+size_t DisassemblerX86::DumpNops(std::ostream& os, const uint8_t* instr) {
+static constexpr uint8_t kNops[][10] = {
+ { },
+ { 0x90 },
+ { 0x66, 0x90 },
+ { 0x0f, 0x1f, 0x00 },
+ { 0x0f, 0x1f, 0x40, 0x00 },
+ { 0x0f, 0x1f, 0x44, 0x00, 0x00 },
+ { 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 },
+ { 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00 },
+ { 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
+ { 0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
+ };
+
+ for (size_t i = 1; i < arraysize(kNops); ++i) {
+ if (memcmp(instr, kNops[i], i) == 0) {
+ os << FormatInstructionPointer(instr)
+ << StringPrintf(": %22s \t nop \n", DumpCodeHex(instr, instr + i).c_str());
+ return i;
+ }
+ }
+
+ return 0;
+}
+
size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
+ size_t nop_size = DumpNops(os, instr);
+ if (nop_size != 0u) {
+ return nop_size;
+ }
+
const uint8_t* begin_instr = instr;
bool have_prefixes = true;
uint8_t prefix[4] = {0, 0, 0, 0};
@@ -400,6 +432,7 @@ DISASSEMBLER_ENTRY(cmp,
case 0x89: opcode1 = "mov"; store = true; has_modrm = true; break;
case 0x8A: opcode1 = "mov"; load = true; has_modrm = true; byte_operand = true; break;
case 0x8B: opcode1 = "mov"; load = true; has_modrm = true; break;
+ case 0x9D: opcode1 = "popf"; break;
case 0x0F: // 2 byte extended opcode
instr++;
@@ -541,6 +574,20 @@ DISASSEMBLER_ENTRY(cmp,
load = true;
src_reg_file = dst_reg_file = SSE;
break;
+ case 0x29:
+ opcode1 = "pcmpeqq";
+ prefix[2] = 0;
+ has_modrm = true;
+ load = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ case 0x39:
+ opcode1 = "pcmpgtq";
+ prefix[2] = 0;
+ has_modrm = true;
+ load = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
case 0x40:
opcode1 = "pmulld";
prefix[2] = 0;
@@ -565,7 +612,7 @@ DISASSEMBLER_ENTRY(cmp,
opcode1 = "roundss";
prefix[2] = 0;
has_modrm = true;
- store = true;
+ load = true;
src_reg_file = SSE;
dst_reg_file = SSE;
immediate_bytes = 1;
@@ -574,7 +621,7 @@ DISASSEMBLER_ENTRY(cmp,
opcode1 = "roundsd";
prefix[2] = 0;
has_modrm = true;
- store = true;
+ load = true;
src_reg_file = SSE;
dst_reg_file = SSE;
immediate_bytes = 1;
@@ -704,6 +751,24 @@ DISASSEMBLER_ENTRY(cmp,
load = true;
has_modrm = true;
break;
+ case 0x64:
+ case 0x65:
+ case 0x66:
+ if (prefix[2] == 0x66) {
+ src_reg_file = dst_reg_file = SSE;
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else {
+ src_reg_file = dst_reg_file = MMX;
+ }
+ switch (*instr) {
+ case 0x64: opcode1 = "pcmpgtb"; break;
+ case 0x65: opcode1 = "pcmpgtw"; break;
+ case 0x66: opcode1 = "pcmpgtd"; break;
+ }
+ prefix[2] = 0;
+ has_modrm = true;
+ load = true;
+ break;
case 0x6E:
if (prefix[2] == 0x66) {
dst_reg_file = SSE;
@@ -799,6 +864,24 @@ DISASSEMBLER_ENTRY(cmp,
store = true;
immediate_bytes = 1;
break;
+ case 0x74:
+ case 0x75:
+ case 0x76:
+ if (prefix[2] == 0x66) {
+ src_reg_file = dst_reg_file = SSE;
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else {
+ src_reg_file = dst_reg_file = MMX;
+ }
+ switch (*instr) {
+ case 0x74: opcode1 = "pcmpeqb"; break;
+ case 0x75: opcode1 = "pcmpeqw"; break;
+ case 0x76: opcode1 = "pcmpeqd"; break;
+ }
+ prefix[2] = 0;
+ has_modrm = true;
+ load = true;
+ break;
case 0x7C:
if (prefix[0] == 0xF2) {
opcode1 = "haddps";
@@ -826,6 +909,22 @@ DISASSEMBLER_ENTRY(cmp,
has_modrm = true;
store = true;
break;
+ case 0x7F:
+ if (prefix[2] == 0x66) {
+ src_reg_file = dst_reg_file = SSE;
+ opcode1 = "movdqa";
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF3) {
+ src_reg_file = dst_reg_file = SSE;
+ opcode1 = "movdqu";
+ prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else {
+ dst_reg_file = MMX;
+ opcode1 = "movq";
+ }
+ store = true;
+ has_modrm = true;
+ break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
opcode1 = "j";
@@ -1034,6 +1133,22 @@ DISASSEMBLER_ENTRY(cmp,
opcode1 = opcode_tmp.c_str();
}
break;
+ case 0xE0:
+ case 0xE3:
+ if (prefix[2] == 0x66) {
+ src_reg_file = dst_reg_file = SSE;
+ prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode
+ } else {
+ src_reg_file = dst_reg_file = MMX;
+ }
+ switch (*instr) {
+ case 0xE0: opcode1 = "pavgb"; break;
+ case 0xE3: opcode1 = "pavgw"; break;
+ }
+ prefix[2] = 0;
+ has_modrm = true;
+ load = true;
+ break;
case 0xEB:
if (prefix[2] == 0x66) {
src_reg_file = dst_reg_file = SSE;
@@ -1257,7 +1372,7 @@ DISASSEMBLER_ENTRY(cmp,
has_modrm = true;
reg_is_opcode = true;
store = true;
- immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0;
+ immediate_bytes = ((instr[1] & 0x38) == 0) ? (instr[0] == 0xF7 ? 4 : 1) : 0;
break;
case 0xFF:
{
@@ -1377,11 +1492,11 @@ DISASSEMBLER_ENTRY(cmp,
}
if (prefix[1] == kFs && !supports_rex_) {
args << " ; ";
- Thread::DumpThreadOffset<4>(args, address_bits);
+ GetDisassemblerOptions()->thread_offset_name_function_(args, address_bits);
}
if (prefix[1] == kGs && supports_rex_) {
args << " ; ";
- Thread::DumpThreadOffset<8>(args, address_bits);
+ GetDisassemblerOptions()->thread_offset_name_function_(args, address_bits);
}
const char* prefix_str;
switch (prefix[0]) {