in runtime/disassembler-x64.cpp [1621:1959]
int DisassemblerX64::instructionDecode(uword pc) {
uint8_t* data = reinterpret_cast<uint8_t*>(pc);
const bool processed = decodeInstructionType(&data);
if (!processed) {
switch (*data) {
case 0xC2:
print("ret ");
printImmediateValue(*reinterpret_cast<uint16_t*>(data + 1));
data += 3;
break;
case 0xC8:
print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]);
data += 4;
break;
case 0x69:
FALLTHROUGH;
case 0x6B: {
int mod, regop, rm;
getModRM(*(data + 1), &mod, ®op, &rm);
int32_t imm = *data == 0x6B
? *(data + 2)
: LoadUnaligned(reinterpret_cast<int32_t*>(data + 2));
print("imul%s %s,%s,", operandSizeCode(), nameOfCPURegister(regop),
nameOfCPURegister(rm));
printImmediateValue(imm);
data += 2 + (*data == 0x6B ? 1 : 4);
break;
}
case 0x81:
FALLTHROUGH;
case 0x83: // 0x81 with sign extension bit set
data += printImmediateOp(data);
break;
case 0x0F:
data += twoByteOpcodeInstruction(data);
break;
case 0x8F: {
data++;
int mod, regop, rm;
getModRM(*data, &mod, ®op, &rm);
if (regop == 0) {
print("pop ");
data += printRightOperand(data);
}
} break;
case 0xFF: {
data++;
int mod, regop, rm;
getModRM(*data, &mod, ®op, &rm);
const char* mnem = nullptr;
switch (regop) {
case 0:
mnem = "inc";
break;
case 1:
mnem = "dec";
break;
case 2:
mnem = "call";
break;
case 4:
mnem = "jmp";
break;
case 6:
mnem = "push";
break;
default:
mnem = "???";
}
if (regop <= 1) {
print("%s%s ", mnem, operandSizeCode());
} else {
print("%s ", mnem);
}
data += printRightOperand(data);
} break;
case 0xC7: // imm32, fall through
case 0xC6: // imm8
{
bool is_byte = *data == 0xC6;
data++;
if (is_byte) {
print("movb ");
data += printRightByteOperand(data);
print(",");
data += printImmediate(data, BYTE_SIZE);
} else {
print("mov%s ", operandSizeCode());
data += printRightOperand(data);
print(",");
data += printImmediate(data, operandSize(), /* sign extend = */ true);
}
} break;
case 0x80: {
byte_size_operand_ = true;
data += printImmediateOp(data);
} break;
case 0x88: // 8bit, fall through
case 0x89: // 32bit
{
bool is_byte = *data == 0x88;
int mod, regop, rm;
data++;
getModRM(*data, &mod, ®op, &rm);
if (is_byte) {
print("movb ");
data += printRightByteOperand(data);
print(",%s", nameOfByteCPURegister(regop));
} else {
print("mov%s ", operandSizeCode());
data += printRightOperand(data);
print(",%s", nameOfCPURegister(regop));
}
} break;
case 0x90:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x95:
case 0x96:
case 0x97: {
int reg = (*data & 0x7) | (rexB() ? 8 : 0);
if (reg == 0) {
print("nop"); // Common name for xchg rax,rax.
} else {
print("xchg%s %s, %s", operandSizeCode(), rax(),
nameOfCPURegister(reg));
}
data++;
} break;
case 0xB0:
case 0xB1:
case 0xB2:
case 0xB3:
case 0xB4:
case 0xB5:
case 0xB6:
case 0xB7:
case 0xB8:
case 0xB9:
case 0xBA:
case 0xBB:
case 0xBC:
case 0xBD:
case 0xBE:
case 0xBF: {
// mov reg8,imm8 or mov reg32,imm32
uint8_t opcode = *data;
data++;
const bool is_not_8bit = opcode >= 0xB8;
int reg = (opcode & 0x7) | (rexB() ? 8 : 0);
if (is_not_8bit) {
print("mov%s %s,", operandSizeCode(), nameOfCPURegister(reg));
data +=
printImmediate(data, operandSize(), /* sign extend = */ false);
} else {
print("movb %s,", nameOfByteCPURegister(reg));
data += printImmediate(data, BYTE_SIZE, /* sign extend = */ false);
}
break;
}
case 0xFE: {
data++;
int mod, regop, rm;
getModRM(*data, &mod, ®op, &rm);
if (regop == 1) {
print("decb ");
data += printRightByteOperand(data);
} else {
unimplementedInstruction();
}
break;
}
case 0x68:
print("push ");
printImmediateValue(
LoadUnaligned(reinterpret_cast<int32_t*>(data + 1)));
data += 5;
break;
case 0x6A:
print("push ");
printImmediateValue(*reinterpret_cast<int8_t*>(data + 1));
data += 2;
break;
case 0xA1:
FALLTHROUGH;
case 0xA3:
switch (operandSize()) {
case DOUBLEWORD_SIZE: {
printAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
if (*data == 0xA1) { // Opcode 0xA1
print("movzxlq %s,(", rax());
printAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
print(")");
} else { // Opcode 0xA3
print("movzxlq (");
printAddress(reinterpret_cast<uint8_t*>(
*reinterpret_cast<int32_t*>(data + 1)));
print("),%s", rax());
}
data += 5;
break;
}
case QUADWORD_SIZE: {
// New x64 instruction mov rax,(imm_64).
if (*data == 0xA1) { // Opcode 0xA1
print("movq %s,(", rax());
printAddress(*reinterpret_cast<uint8_t**>(data + 1));
print(")");
} else { // Opcode 0xA3
print("movq (");
printAddress(*reinterpret_cast<uint8_t**>(data + 1));
print("),%s", rax());
}
data += 9;
break;
}
default:
unimplementedInstruction();
data += 2;
}
break;
case 0xA8:
print("test al,");
printImmediateValue(*reinterpret_cast<uint8_t*>(data + 1));
data += 2;
break;
case 0xA9: {
data++;
print("test%s %s,", operandSizeCode(), rax());
data += printImmediate(data, operandSize());
break;
}
case 0xD1:
FALLTHROUGH;
case 0xD3:
FALLTHROUGH;
case 0xC1:
data += shiftInstruction(data);
break;
case 0xD0:
FALLTHROUGH;
case 0xD2:
FALLTHROUGH;
case 0xC0:
byte_size_operand_ = true;
data += shiftInstruction(data);
break;
case 0xD9:
FALLTHROUGH;
case 0xDA:
FALLTHROUGH;
case 0xDB:
FALLTHROUGH;
case 0xDC:
FALLTHROUGH;
case 0xDD:
FALLTHROUGH;
case 0xDE:
FALLTHROUGH;
case 0xDF:
data += fPUInstruction(data);
break;
case 0xEB:
data += jumpShort(data);
break;
case 0xF6:
byte_size_operand_ = true;
FALLTHROUGH;
case 0xF7:
data += f6F7Instruction(data);
break;
case 0x0c:
case 0x3c:
data += printImmediateOp(data);
break;
// These encodings for inc and dec are IA32 only, but we don't get here
// on X64 - the REX prefix recoginizer catches them earlier.
case 0x40:
case 0x41:
case 0x42:
case 0x43:
case 0x44:
case 0x45:
case 0x46:
case 0x47:
print("inc %s", nameOfCPURegister(*data & 7));
data += 1;
break;
case 0x48:
case 0x49:
case 0x4a:
case 0x4b:
case 0x4c:
case 0x4d:
case 0x4e:
case 0x4f:
print("dec %s", nameOfCPURegister(*data & 7));
data += 1;
break;
default:
unimplementedInstruction();
data += 1;
}
} // !processed
DCHECK(buffer_[buffer_pos_] == '\0', "");
int instr_len = data - reinterpret_cast<uint8_t*>(pc);
DCHECK(instr_len > 0, ""); // Ensure progress.
return instr_len;
}