int DisassemblerX64::instructionDecode()

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, &regop, &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, &regop, &rm);
        if (regop == 0) {
          print("pop ");
          data += printRightOperand(data);
        }
      } break;

      case 0xFF: {
        data++;
        int mod, regop, rm;
        getModRM(*data, &mod, &regop, &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, &regop, &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, &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:
        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;
}