int DisassemblerX64::InstructionDecode()

in runtime/vm/compiler/assembler/disassembler_x86.cc [1645:1989]


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:
        FALL_THROUGH;
      case 0x6B: {
        int mod, regop, rm;
        get_modrm(*(data + 1), &mod, &regop, &rm);
        int32_t imm = *data == 0x6B
                          ? *(data + 2)
                          : LoadUnaligned(reinterpret_cast<int32_t*>(data + 2));
        Print("imul%s %s,%s,", operand_size_code(), NameOfCPURegister(regop),
              NameOfCPURegister(rm));
        PrintImmediateValue(imm);
        data += 2 + (*data == 0x6B ? 1 : 4);
        break;
      }

      case 0x81:
        FALL_THROUGH;
      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;
        get_modrm(*data, &mod, &regop, &rm);
        if (regop == 0) {
          Print("pop ");
          data += PrintRightOperand(data);
        }
      } break;

      case 0xFF: {
        data++;
        int mod, regop, rm;
        get_modrm(*data, &mod, &regop, &rm);
        const char* mnem = NULL;
        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, operand_size_code());
        } 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 ", operand_size_code());
          data += PrintRightOperand(data);
          Print(",");
          data +=
              PrintImmediate(data, operand_size(), /* 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++;
        get_modrm(*data, &mod, &regop, &rm);
        if (is_byte) {
          Print("movb ");
          data += PrintRightByteOperand(data);
          Print(",%s", NameOfByteCPURegister(regop));
        } else {
          Print("mov%s ", operand_size_code());
          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) | (rex_b() ? 8 : 0);
        if (reg == 0) {
          Print("nop");  // Common name for xchg rax,rax.
        } else {
          Print("xchg%s %s, %s", operand_size_code(), 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) | (rex_b() ? 8 : 0);
        if (is_not_8bit) {
          Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
          data +=
              PrintImmediate(data, operand_size(), /* 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;
        get_modrm(*data, &mod, &regop, &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:
        FALL_THROUGH;
      case 0xA3:
        switch (operand_size()) {
          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,", operand_size_code(), Rax());
        data += PrintImmediate(data, operand_size());
        break;
      }
      case 0xD1:
        FALL_THROUGH;
      case 0xD3:
        FALL_THROUGH;
      case 0xC1:
        data += ShiftInstruction(data);
        break;
      case 0xD0:
        FALL_THROUGH;
      case 0xD2:
        FALL_THROUGH;
      case 0xC0:
        byte_size_operand_ = true;
        data += ShiftInstruction(data);
        break;

      case 0xD9:
        FALL_THROUGH;
      case 0xDA:
        FALL_THROUGH;
      case 0xDB:
        FALL_THROUGH;
      case 0xDC:
        FALL_THROUGH;
      case 0xDD:
        FALL_THROUGH;
      case 0xDE:
        FALL_THROUGH;
      case 0xDF:
        data += FPUInstruction(data);
        break;

      case 0xEB:
        data += JumpShort(data);
        break;

      case 0xF6:
        byte_size_operand_ = true;
        FALL_THROUGH;
      case 0xF7:
        data += F6F7Instruction(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;

#if defined(TARGET_ARCH_IA32)
      case 0x61:
        Print("popad");
        break;

      case 0x60:
        Print("pushad");
        break;
#endif

      default:
        UnimplementedInstruction();
        data += 1;
    }
  }  // !processed

  ASSERT(buffer_[buffer_pos_] == '\0');

  int instr_len = data - reinterpret_cast<uint8_t*>(pc);
  ASSERT(instr_len > 0);  // Ensure progress.

  return instr_len;
}