2015-05-16 11:05:17 +08:00
|
|
|
|
/***************************************************************************************************
|
2014-10-25 05:11:16 +08:00
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
Zyan Disassembler Engine
|
2014-10-25 05:11:16 +08:00
|
|
|
|
Version 1.0
|
|
|
|
|
|
|
|
|
|
Remarks : Freeware, Copyright must be included
|
|
|
|
|
|
|
|
|
|
Original Author : Florian Bernd
|
2015-05-16 11:05:17 +08:00
|
|
|
|
Modifications : Joel H<EFBFBD>ner
|
2014-10-25 05:11:16 +08:00
|
|
|
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
|
* furnished to do so, subject to the following conditions:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
*
|
2014-10-25 05:11:16 +08:00
|
|
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
|
|
|
* copies or substantial portions of the Software.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
*
|
2014-10-25 05:11:16 +08:00
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
***************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "ZydisInstructionDecoder.hpp"
|
2015-02-05 05:08:16 +08:00
|
|
|
|
#include <cstring>
|
2014-10-25 05:11:16 +08:00
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
namespace Zydis
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* InstructionDecoder ====================================================================== */
|
|
|
|
|
|
|
|
|
|
bool InstructionDecoder::decodeRegisterOperand(InstructionInfo& info,
|
|
|
|
|
OperandInfo& operand, RegisterClass registerClass, uint8_t registerId,
|
|
|
|
|
DefinedOperandSize operandSize) const
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
Register reg = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
uint16_t size = getEffectiveOperandSize(info, operandSize);
|
|
|
|
|
switch (registerClass)
|
|
|
|
|
{
|
|
|
|
|
case RegisterClass::GENERAL_PURPOSE:
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case 64:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::RAX) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 32:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::EAX) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 16:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::AX) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
// TODO: Only REX? Or VEX too?
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (m_disassemblerMode == DisassemblerMode::M64BIT && (info.flags & IF_PREFIX_REX))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (registerId >= 4)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::SPL) + (registerId - 4));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::AL) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::AL) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0:
|
|
|
|
|
// TODO: Error?
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case RegisterClass::MMX:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
2015-05-21 07:07:19 +08:00
|
|
|
|
static_cast<uint16_t>(Register::MM0) + (registerId & 0x07));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case RegisterClass::CONTROL:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(static_cast<uint16_t>(Register::CR0) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case RegisterClass::DEBUG:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(static_cast<uint16_t>(Register::DR0) + registerId);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case RegisterClass::SEGMENT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((registerId & 7) > 5)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(
|
2015-05-21 07:07:19 +08:00
|
|
|
|
static_cast<uint16_t>(Register::ES) + (registerId & 0x07));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case RegisterClass::XMM:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
reg = static_cast<Register>(registerId + static_cast<uint16_t>(
|
|
|
|
|
((size == 256) ? Register::YMM0 : Register::XMM0)));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::REGISTER;
|
|
|
|
|
operand.base = static_cast<Register>(reg);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.size = size;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeRegisterMemoryOperand(InstructionInfo& info,
|
|
|
|
|
OperandInfo& operand, RegisterClass registerClass, DefinedOperandSize operandSize)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
assert(info.flags & IF_MODRM);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode register operand
|
|
|
|
|
if (info.modrm_mod == 3)
|
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, registerClass, info.modrm_rm_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
|
|
|
|
}
|
|
|
|
|
// Decode memory operand
|
|
|
|
|
uint8_t offset = 0;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::MEMORY;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.size = getEffectiveOperandSize(info, operandSize);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
switch (info.address_mode)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
case 16:
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static const Register bases[] = {
|
|
|
|
|
Register::BX, Register::BX, Register::BP, Register::BP,
|
|
|
|
|
Register::SI, Register::DI, Register::BP, Register::BX };
|
|
|
|
|
static const Register indices[] = {
|
|
|
|
|
Register::SI, Register::DI, Register::SI, Register::DI,
|
|
|
|
|
Register::NONE, Register::NONE, Register::NONE,
|
|
|
|
|
Register::NONE };
|
2015-05-21 07:07:19 +08:00
|
|
|
|
operand.base = static_cast<Register>(bases[info.modrm_rm_ext & 0x07]);
|
|
|
|
|
operand.index = static_cast<Register>(indices[info.modrm_rm_ext & 0x07]);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.modrm_mod == 0 && info.modrm_rm_ext == 6) {
|
2014-10-25 05:11:16 +08:00
|
|
|
|
offset = 16;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
} else if (info.modrm_mod == 1) {
|
|
|
|
|
offset = 8;
|
|
|
|
|
} else if (info.modrm_mod == 2) {
|
|
|
|
|
offset = 16;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 32:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::EAX) + info.modrm_rm_ext);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (info.modrm_mod)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (info.modrm_rm_ext == 5)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
offset = 32;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
offset = 8;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
offset = 32;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.modrm_rm_ext & 0x07) == 4)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (!decodeSIB(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
operand.base =
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static_cast<Register>(static_cast<uint16_t>(Register::EAX) +
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.sib_base_ext);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.index =
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static_cast<Register>(static_cast<uint16_t>(Register::EAX) +
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.sib_index_ext);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
operand.scale = (1 << info.sib_scale) & ~1;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (operand.index == Register::ESP)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.index = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (operand.base == Register::EBP)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (info.modrm_mod == 0)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
if (info.modrm_mod == 1)
|
|
|
|
|
{
|
|
|
|
|
offset = 8;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
offset = 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.index = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 64:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = static_cast<Register>(
|
|
|
|
|
static_cast<uint16_t>(Register::RAX) + info.modrm_rm_ext);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (info.modrm_mod)
|
|
|
|
|
{
|
|
|
|
|
case 0:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.modrm_rm_ext & 0x07) == 5)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_RELATIVE;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = Register::RIP;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
offset = 32;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 1:
|
|
|
|
|
offset = 8;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
|
|
|
|
offset = 32;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.modrm_rm_ext & 0x07) == 4)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (!decodeSIB(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
operand.base =
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static_cast<Register>(static_cast<uint16_t>(Register::RAX) +
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.sib_base_ext);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.index =
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static_cast<Register>(static_cast<uint16_t>(Register::RAX) +
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.sib_index_ext);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (operand.index == Register::RSP)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.index = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
operand.scale = (1 << info.sib_scale) & ~1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if ((operand.base == Register::RBP) || (operand.base == Register::R13))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (info.modrm_mod == 0)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.base = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
if (info.modrm_mod == 1)
|
|
|
|
|
{
|
|
|
|
|
offset = 8;
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
offset = 32;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.index = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (offset)
|
|
|
|
|
{
|
|
|
|
|
if (!decodeDisplacement(info, operand, offset))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
operand.offset = 0;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeImmediate(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
DefinedOperandSize operandSize)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::IMMEDIATE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.size = getEffectiveOperandSize(info, operandSize);
|
|
|
|
|
switch (operand.size)
|
|
|
|
|
{
|
|
|
|
|
case 8:
|
|
|
|
|
operand.lval.ubyte = inputNext(info);
|
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
operand.lval.uword = inputNext<uint16_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
case 32:
|
|
|
|
|
operand.lval.udword = inputNext<uint32_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
case 64:
|
|
|
|
|
operand.lval.uqword = inputNext<uint64_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// TODO: Maybe return false instead of assert
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!operand.lval.uqword && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeDisplacement(InstructionInfo& info,
|
|
|
|
|
OperandInfo& operand, uint8_t size)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
switch (size)
|
|
|
|
|
{
|
|
|
|
|
case 8:
|
|
|
|
|
operand.offset = 8;
|
|
|
|
|
operand.lval.ubyte = inputNext(info);
|
|
|
|
|
break;
|
|
|
|
|
case 16:
|
|
|
|
|
operand.offset = 16;
|
|
|
|
|
operand.lval.uword = inputNext<uint16_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
case 32:
|
|
|
|
|
operand.offset = 32;
|
|
|
|
|
operand.lval.udword = inputNext<uint32_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
case 64:
|
|
|
|
|
operand.offset = 64;
|
|
|
|
|
operand.lval.uqword = inputNext<uint64_t>(info);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
// TODO: Maybe return false instead of assert
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!operand.lval.uqword && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeModrm(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!(info.flags & IF_MODRM))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.modrm = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.modrm && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
info.flags |= IF_MODRM;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.modrm_mod = (info.modrm >> 6) & 0x03;
|
|
|
|
|
info.modrm_reg = (info.modrm >> 3) & 0x07;
|
|
|
|
|
info.modrm_rm = (info.modrm >> 0) & 0x07;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// The @c decodeModrm method might get called multiple times during the opcode- and the
|
|
|
|
|
// operand decoding, but the effective REX/VEX fields are not initialized before the end of
|
|
|
|
|
// the opcode decoding process. As the extended values are only used for the operand decoding,
|
|
|
|
|
// we should have no problems.
|
|
|
|
|
info.modrm_reg_ext = (info.eff_rexvex_r << 3) | info.modrm_reg;
|
|
|
|
|
info.modrm_rm_ext = (info.eff_rexvex_b << 3) | info.modrm_rm;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeSIB(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
assert(info.flags & IF_MODRM);
|
|
|
|
|
assert((info.modrm_rm & 0x7) == 4);
|
|
|
|
|
if (!(info.flags & IF_SIB))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.sib = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.sib && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
info.flags |= IF_SIB;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.sib_scale = (info.sib >> 6) & 0x03;
|
|
|
|
|
info.sib_index = (info.sib >> 3) & 0x07;
|
|
|
|
|
info.sib_base = (info.sib >> 0) & 0x07;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// The @c decodeSib method is only called during the operand decoding, so updating the
|
|
|
|
|
// extended values at this point should be safe.
|
|
|
|
|
info.sib_index_ext = (info.eff_rexvex_x << 3) | info.sib_index;
|
|
|
|
|
info.sib_base_ext = (info.eff_rexvex_b << 3) | info.sib_base;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeVex(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!(info.flags & IF_PREFIX_VEX))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.vex_op = inputCurrent();
|
|
|
|
|
switch (info.vex_op)
|
|
|
|
|
{
|
|
|
|
|
case 0xC4:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.vex_b1 = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.vex_b1 || (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.vex_b2 = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.vex_b2 || (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.vex_r = (info.vex_b1 >> 7) & 0x01;
|
|
|
|
|
info.vex_x = (info.vex_b1 >> 6) & 0x01;
|
|
|
|
|
info.vex_b = (info.vex_b1 >> 5) & 0x01;
|
|
|
|
|
info.vex_m_mmmm = (info.vex_b1 >> 0) & 0x1F;
|
|
|
|
|
info.vex_w = (info.vex_b2 >> 7) & 0x01;
|
|
|
|
|
info.vex_vvvv = (info.vex_b2 >> 3) & 0x0F;
|
|
|
|
|
info.vex_l = (info.vex_b2 >> 2) & 0x01;
|
|
|
|
|
info.vex_pp = (info.vex_b2 >> 0) & 0x03;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0xC5:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.vex_b1 = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.vex_b1 || (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.vex_r = (info.vex_b1 >> 7) & 0x01;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.vex_x = 1;
|
|
|
|
|
info.vex_b = 1;
|
|
|
|
|
info.vex_m_mmmm = 1;
|
|
|
|
|
info.vex_w = 0;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.vex_vvvv = (info.vex_b1 >> 3) & 0x0F;
|
|
|
|
|
info.vex_l = (info.vex_b1 >> 2) & 0x01;
|
|
|
|
|
info.vex_pp = (info.vex_b1 >> 0) & 0x03;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
if (info.vex_m_mmmm > 3)
|
|
|
|
|
{
|
|
|
|
|
// TODO: Add proper error flag
|
|
|
|
|
info.flags |= IF_ERROR_MASK;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
info.flags |= IF_PREFIX_VEX;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint16_t InstructionDecoder::getEffectiveOperandSize(const InstructionInfo& info,
|
|
|
|
|
DefinedOperandSize operandSize) const
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
switch (operandSize)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandSize::NA:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return 0;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandSize::Z:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return (info.operand_mode == 16) ? 16 : 32;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandSize::V:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return info.operand_mode;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandSize::Y:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return (info.operand_mode == 16) ? 32 : info.operand_mode;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandSize::X:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
assert(info.vex_op != 0);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return (info.eff_vex_l) ?
|
2015-05-16 11:05:17 +08:00
|
|
|
|
getEffectiveOperandSize(info, DefinedOperandSize::QQ) :
|
|
|
|
|
getEffectiveOperandSize(info, DefinedOperandSize::DQ);
|
|
|
|
|
case DefinedOperandSize::RDQ:
|
|
|
|
|
return (m_disassemblerMode == DisassemblerMode::M64BIT) ? 64 : 32;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
default:
|
2015-05-16 11:05:17 +08:00
|
|
|
|
return Internal::GetSimpleOperandSize(operandSize);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeOperands(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
assert(info.instrDefinition);
|
|
|
|
|
// Always try to decode the first operand
|
|
|
|
|
if (!decodeOperand(info, info.operand[0], info.instrDefinition->operand[0].type,
|
|
|
|
|
info.instrDefinition->operand[0].size))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Decode other operands on demand
|
|
|
|
|
for (unsigned int i = 1; i < 4; ++i)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.operand[i - 1].type != OperandType::NONE)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
if (!decodeOperand(info, info.operand[i], info.instrDefinition->operand[i].type,
|
|
|
|
|
info.instrDefinition->operand[i].size))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Update operand access modes
|
2014-10-30 23:36:25 +08:00
|
|
|
|
for (unsigned int i = 0; i < 4; ++i)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.operand[i].type != OperandType::NONE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[i].access_mode = OperandAccessMode::READ;
|
2014-10-30 23:36:25 +08:00
|
|
|
|
if (i == 0)
|
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.instrDefinition->flags & IDF_OPERAND1_WRITE)
|
2014-10-30 23:36:25 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[0].access_mode = OperandAccessMode::WRITE;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.instrDefinition->flags & IDF_OPERAND1_READWRITE)
|
2014-10-30 23:36:25 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[0].access_mode = OperandAccessMode::READWRITE;
|
2014-10-30 23:36:25 +08:00
|
|
|
|
}
|
|
|
|
|
} else if (i == 1)
|
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.instrDefinition->flags & IDF_OPERAND2_WRITE)
|
2014-10-30 23:36:25 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].access_mode = OperandAccessMode::WRITE;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.instrDefinition->flags & IDF_OPERAND2_READWRITE)
|
2014-10-30 23:36:25 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].access_mode = OperandAccessMode::READWRITE;
|
2014-10-30 23:36:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeOperand(InstructionInfo& info, OperandInfo& operand,
|
|
|
|
|
DefinedOperandType operandType, DefinedOperandSize operandSize)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
using namespace Internal;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (operandType)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::NONE:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::A:
|
|
|
|
|
operand.type = OperandType::POINTER;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (info.operand_mode == 16)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
operand.size = 32;
|
|
|
|
|
operand.lval.ptr.off = inputNext<uint16_t>(info);
|
|
|
|
|
operand.lval.ptr.seg = inputNext<uint16_t>(info);
|
|
|
|
|
} else {
|
|
|
|
|
operand.size = 48;
|
|
|
|
|
operand.lval.ptr.off = inputNext<uint32_t>(info);
|
|
|
|
|
operand.lval.ptr.seg = inputNext<uint16_t>(info);
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((!operand.lval.ptr.off || !operand.lval.ptr.seg) && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::C:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::CONTROL, info.modrm_reg_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::D:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::DEBUG, info.modrm_reg_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::F:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// TODO: FAR flag
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::M:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// ModR/M byte may refer only to a register
|
|
|
|
|
if (info.modrm_mod == 3)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::E:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::GENERAL_PURPOSE,
|
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::G:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::GENERAL_PURPOSE,
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.modrm_reg_ext, operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::H:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
assert(info.vex_op != 0);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::XMM, (0xF & ~info.vex_vvvv),
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::sI:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
operand.signed_lval = true;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::I:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeImmediate(info, operand, operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::I1:
|
|
|
|
|
operand.type = OperandType::CONSTANT;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.lval.udword = 1;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::J:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
if (!decodeImmediate(info, operand, operandSize))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::REL_IMMEDIATE;
|
2014-10-30 06:26:17 +08:00
|
|
|
|
operand.signed_lval = true;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.flags |= IF_RELATIVE;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::L:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
assert(info.vex_op != 0);
|
|
|
|
|
uint8_t imm = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!imm && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
uint8_t mask = (m_disassemblerMode == DisassemblerMode::M64BIT) ? 0xF : 0x7;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::XMM, mask & (imm >> 4),
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::MR:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::GENERAL_PURPOSE,
|
|
|
|
|
info.modrm_mod == 3 ?
|
2015-05-16 11:05:17 +08:00
|
|
|
|
GetComplexOperandRegSize(operandSize) :
|
|
|
|
|
GetComplexOperandMemSize(operandSize));
|
|
|
|
|
case DefinedOperandType::MU:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::XMM,
|
|
|
|
|
info.modrm_mod == 3 ?
|
2015-05-16 11:05:17 +08:00
|
|
|
|
GetComplexOperandRegSize(operandSize) :
|
|
|
|
|
GetComplexOperandMemSize(operandSize));
|
|
|
|
|
case DefinedOperandType::N:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// ModR/M byte may refer only to memory
|
|
|
|
|
if (info.modrm_mod != 3)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::Q:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::MMX, operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::O:
|
|
|
|
|
operand.type = OperandType::MEMORY;
|
|
|
|
|
operand.base = Register::NONE;
|
|
|
|
|
operand.index = Register::NONE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.scale = 0;
|
|
|
|
|
operand.size = getEffectiveOperandSize(info, operandSize);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
return decodeDisplacement(info, operand, info.address_mode);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::P:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::MMX, info.modrm_reg_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::R:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// ModR/M byte may refer only to memory
|
|
|
|
|
if (info.modrm_mod != 3)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::GENERAL_PURPOSE,
|
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::S:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::SEGMENT, info.modrm_reg_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::U:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// ModR/M byte may refer only to memory
|
|
|
|
|
if (info.modrm_mod != 3)
|
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::W:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterMemoryOperand(info, operand, RegisterClass::XMM, operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::V:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::XMM, info.modrm_reg_ext,
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::R0:
|
|
|
|
|
case DefinedOperandType::R1:
|
|
|
|
|
case DefinedOperandType::R2:
|
|
|
|
|
case DefinedOperandType::R3:
|
|
|
|
|
case DefinedOperandType::R4:
|
|
|
|
|
case DefinedOperandType::R5:
|
|
|
|
|
case DefinedOperandType::R6:
|
|
|
|
|
case DefinedOperandType::R7:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::GENERAL_PURPOSE,
|
2014-10-27 21:10:22 +08:00
|
|
|
|
((info.eff_rexvex_b << 3) | (static_cast<uint16_t>(operandType) -
|
2015-05-16 11:05:17 +08:00
|
|
|
|
static_cast<uint16_t>(DefinedOperandType::R0))), operandSize);
|
|
|
|
|
case DefinedOperandType::AL:
|
|
|
|
|
case DefinedOperandType::AX:
|
|
|
|
|
case DefinedOperandType::EAX:
|
|
|
|
|
case DefinedOperandType::RAX:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::GENERAL_PURPOSE, 0,
|
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::CL:
|
|
|
|
|
case DefinedOperandType::CX:
|
|
|
|
|
case DefinedOperandType::ECX:
|
|
|
|
|
case DefinedOperandType::RCX:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::GENERAL_PURPOSE, 1,
|
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::DL:
|
|
|
|
|
case DefinedOperandType::DX:
|
|
|
|
|
case DefinedOperandType::EDX:
|
|
|
|
|
case DefinedOperandType::RDX:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return decodeRegisterOperand(info, operand, RegisterClass::GENERAL_PURPOSE, 2,
|
|
|
|
|
operandSize);
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::ES:
|
|
|
|
|
case DefinedOperandType::CS:
|
|
|
|
|
case DefinedOperandType::SS:
|
|
|
|
|
case DefinedOperandType::DS:
|
|
|
|
|
case DefinedOperandType::FS:
|
|
|
|
|
case DefinedOperandType::GS:
|
|
|
|
|
if (m_disassemblerMode == DisassemblerMode::M64BIT)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((operandType != DefinedOperandType::FS) &&
|
2015-05-16 11:05:17 +08:00
|
|
|
|
(operandType != DefinedOperandType::GS))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_OPERAND;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
operand.type = OperandType::REGISTER;
|
|
|
|
|
operand.base = static_cast<Register>((static_cast<uint16_t>(operandType) -
|
|
|
|
|
static_cast<uint16_t>(DefinedOperandType::ES)) +
|
|
|
|
|
static_cast<uint16_t>(Register::ES));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.size = 16;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DefinedOperandType::ST0:
|
|
|
|
|
case DefinedOperandType::ST1:
|
|
|
|
|
case DefinedOperandType::ST2:
|
|
|
|
|
case DefinedOperandType::ST3:
|
|
|
|
|
case DefinedOperandType::ST4:
|
|
|
|
|
case DefinedOperandType::ST5:
|
|
|
|
|
case DefinedOperandType::ST6:
|
|
|
|
|
case DefinedOperandType::ST7:
|
|
|
|
|
operand.type = OperandType::REGISTER;
|
|
|
|
|
operand.base = static_cast<Register>((static_cast<uint16_t>(operandType) -
|
|
|
|
|
static_cast<uint16_t>(DefinedOperandType::ST0)) +
|
|
|
|
|
static_cast<uint16_t>(Register::ST0));
|
2014-10-25 05:11:16 +08:00
|
|
|
|
operand.size = 80;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void InstructionDecoder::resolveOperandAndAddressMode(InstructionInfo& info) const
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
assert(info.instrDefinition);
|
|
|
|
|
switch (m_disassemblerMode)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M16BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.operand_mode = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 32 : 16;
|
|
|
|
|
info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 32 : 16;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M32BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.operand_mode = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 16 : 32;
|
|
|
|
|
info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 16 : 32;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M64BIT:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (info.eff_rexvex_w)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.operand_mode = 64;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if ((info.flags & IF_PREFIX_OPERAND_SIZE))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.operand_mode = 16;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
} else
|
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.operand_mode = (info.instrDefinition->flags & IDF_DEFAULT_64) ? 64 : 32;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.address_mode = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 32 : 64;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
void InstructionDecoder::calculateEffectiveRexVexValues(InstructionInfo& info) const
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
|
|
|
|
assert(info.instrDefinition);
|
|
|
|
|
uint8_t rex = info.rex;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.flags & IF_PREFIX_VEX)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
|
|
|
|
switch (info.vex_op)
|
|
|
|
|
{
|
|
|
|
|
case 0xC4:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
rex = ((~(info.vex_b1 >> 5) & 0x07) | ((info.vex_b2 >> 4) & 0x08));
|
2014-10-27 21:10:22 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0xC5:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
rex = (~(info.vex_b1 >> 5)) & 4;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
rex &= (info.instrDefinition->flags & 0x000F);
|
|
|
|
|
info.eff_rexvex_w = (rex >> 3) & 0x01;
|
|
|
|
|
info.eff_rexvex_r = (rex >> 2) & 0x01;
|
|
|
|
|
info.eff_rexvex_x = (rex >> 1) & 0x01;
|
|
|
|
|
info.eff_rexvex_b = (rex >> 0) & 0x01;
|
|
|
|
|
info.eff_vex_l = info.vex_l && (info.instrDefinition->flags & IDF_ACCEPTS_VEXL);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodePrefixes(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
bool done = false;
|
|
|
|
|
do
|
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
switch (inputPeek(info))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
case 0xF0:
|
|
|
|
|
info.flags |= IF_PREFIX_LOCK;
|
|
|
|
|
break;
|
|
|
|
|
case 0xF2:
|
|
|
|
|
// REPNZ and REPZ are mutally exclusive. The one that comes later has precedence.
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags |= IF_PREFIX_REP;
|
|
|
|
|
info.flags &= ~IF_PREFIX_REPNE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0xF3:
|
|
|
|
|
// REPNZ and REPZ are mutally exclusive. The one that comes later has precedence.
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags |= IF_PREFIX_REP;
|
|
|
|
|
info.flags &= ~IF_PREFIX_REPNE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x2E:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::CS;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x36:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::SS;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x3E:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::DS;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x26:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::ES;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x64:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::FS;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x65:
|
|
|
|
|
info.flags |= IF_PREFIX_SEGMENT;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.segment = Register::GS;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x66:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags |= IF_PREFIX_OPERAND_SIZE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
case 0x67:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags |= IF_PREFIX_ADDRESS_SIZE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((m_disassemblerMode == DisassemblerMode::M64BIT) &&
|
|
|
|
|
(inputCurrent() & 0xF0) == 0x40)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_PREFIX_REX;
|
|
|
|
|
info.rex = inputCurrent();
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
done = true;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// Increase the input offset, if a prefix was found
|
|
|
|
|
if (!done)
|
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (!done);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// TODO: Check for multiple prefixes of the same group
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Parse REX Prefix
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.flags & IF_PREFIX_REX)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
info.rex_w = (info.rex >> 3) & 0x01;
|
|
|
|
|
info.rex_r = (info.rex >> 2) & 0x01;
|
|
|
|
|
info.rex_x = (info.rex >> 1) & 0x01;
|
|
|
|
|
info.rex_b = (info.rex >> 0) & 0x01;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeOpcode(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
using namespace Internal;
|
|
|
|
|
// Read first opcode byte
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Update instruction info
|
|
|
|
|
info.opcode[0] = inputCurrent();
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.opcode_length = 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Iterate through opcode tree
|
2015-05-16 11:05:17 +08:00
|
|
|
|
OpcodeTreeNode node = GetOpcodeTreeChild(GetOpcodeTreeRoot(), inputCurrent());
|
|
|
|
|
OpcodeTreeNodeType nodeType;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
uint16_t index = 0;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
nodeType = GetOpcodeNodeType(node);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (nodeType)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::INSTRUCTION_DEFINITION:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Check for invalid instruction
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (GetOpcodeNodeValue(node) == 0)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags |= IF_ERROR_INVALID;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Get instruction definition
|
2015-05-16 11:05:17 +08:00
|
|
|
|
const InstructionDefinition *instrDefinition =
|
|
|
|
|
GetInstructionDefinition(node);
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Check for invalid 64 bit instruction
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((m_disassemblerMode == DisassemblerMode::M64BIT) &&
|
|
|
|
|
(instrDefinition->flags & IDF_INVALID_64))
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_INVALID_64;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Update instruction info
|
|
|
|
|
info.instrDefinition = instrDefinition;
|
|
|
|
|
info.mnemonic = instrDefinition->mnemonic;
|
|
|
|
|
// Update effective REX/VEX values
|
|
|
|
|
calculateEffectiveRexVexValues(info);
|
|
|
|
|
// Resolve operand and address mode
|
|
|
|
|
resolveOperandAndAddressMode(info);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode operands
|
|
|
|
|
if (!decodeOperands(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::TABLE:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Read next opcode byte
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!inputNext(info) && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Update instruction info
|
2015-05-21 07:07:19 +08:00
|
|
|
|
assert((info.opcode_length > 0) && (info.opcode_length < 3));
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.opcode[info.opcode_length] = inputCurrent();
|
|
|
|
|
info.opcode_length++;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Set child node index for next iteration
|
|
|
|
|
index = inputCurrent();
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::MODRM_MOD:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode modrm byte
|
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
index = (info.modrm_mod == 0x3) ? 1 : 0;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::MODRM_REG:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode modrm byte
|
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
index = info.modrm_reg;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::MODRM_RM:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode modrm byte
|
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
index = info.modrm_rm;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::MANDATORY:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Check if there are any prefixes present
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.flags & IF_PREFIX_REP)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
index = 1; // F2
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.flags & IF_PREFIX_REPNE)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
index = 2; // F3
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.flags & IF_PREFIX_OPERAND_SIZE)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
index = 3; // 66
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (GetOpcodeTreeChild(node, index) == 0)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (index && (GetOpcodeTreeChild(node, index) != 0))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Remove REP and REPNE prefix
|
|
|
|
|
info.flags &= ~IF_PREFIX_REP;
|
|
|
|
|
info.flags &= ~IF_PREFIX_REPNE;
|
|
|
|
|
// Remove OPERAND_SIZE prefix, if it was used as mandatory prefix for the
|
|
|
|
|
// instruction
|
2014-10-25 05:11:16 +08:00
|
|
|
|
if (index == 3)
|
|
|
|
|
{
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags &= ~IF_PREFIX_OPERAND_SIZE;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::X87:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode modrm byte
|
|
|
|
|
if (!decodeModrm(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
index = info.modrm - 0xC0;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::ADDRESS_SIZE:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (m_disassemblerMode)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M16BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 1 : 0;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M32BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 0 : 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M64BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.flags & IF_PREFIX_ADDRESS_SIZE) ? 1 : 2;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::OPERAND_SIZE:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (m_disassemblerMode)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M16BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 1 : 0;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M32BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.flags & IF_PREFIX_OPERAND_SIZE) ? 0 : 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M64BIT:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
index = (info.rex_w) ? 2 : ((info.flags & IF_PREFIX_OPERAND_SIZE) ? 0 : 1);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::MODE:
|
|
|
|
|
index = (m_disassemblerMode != DisassemblerMode::M64BIT) ? 0 : 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::VENDOR:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (m_preferredVendor)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case InstructionSetVendor::ANY:
|
|
|
|
|
index = (GetOpcodeTreeChild(node, 0) != 0) ? 0 : 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case InstructionSetVendor::INTEL:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
index = 1;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case InstructionSetVendor::AMD:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
index = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::AMD3DNOW:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
// As all 3dnow instructions got the same operands and flag definitions, we just
|
|
|
|
|
// decode a random instruction and determine the specific opcode later.
|
2015-05-16 11:05:17 +08:00
|
|
|
|
assert(GetOpcodeTreeChild(node, 0x0C) != 0);
|
|
|
|
|
const InstructionDefinition *instrDefinition =
|
|
|
|
|
GetInstructionDefinition(GetOpcodeTreeChild(node, 0x0C));
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Update instruction info
|
|
|
|
|
info.instrDefinition = instrDefinition;
|
|
|
|
|
info.mnemonic = instrDefinition->mnemonic;
|
|
|
|
|
// Update effective REX/VEX values
|
|
|
|
|
calculateEffectiveRexVexValues(info);
|
|
|
|
|
// Resolve operand and address mode
|
|
|
|
|
resolveOperandAndAddressMode(info);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode operands
|
|
|
|
|
if (!decodeOperands(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// Read the actual 3dnow opcode
|
|
|
|
|
info.opcode[2] = inputNext(info);
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (!info.opcode[2] && (info.flags & IF_ERROR_MASK))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Update instruction info
|
|
|
|
|
instrDefinition =
|
2015-05-16 11:05:17 +08:00
|
|
|
|
GetInstructionDefinition(GetOpcodeTreeChild(node, info.opcode[2]));
|
2014-10-27 21:10:22 +08:00
|
|
|
|
if (!instrDefinition ||
|
2015-05-16 11:05:17 +08:00
|
|
|
|
(instrDefinition->mnemonic == InstructionMnemonic::INVALID))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags |= IF_ERROR_INVALID;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
info.instrDefinition = instrDefinition;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.mnemonic = instrDefinition->mnemonic;
|
|
|
|
|
// Update operand access modes
|
|
|
|
|
for (unsigned int i = 0; i < 4; ++i)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.operand[i].type != OperandType::NONE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[i - 1].access_mode = OperandAccessMode::READ;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.operand[0].type != OperandType::NONE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.instrDefinition->flags & IDF_OPERAND1_WRITE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[0].access_mode = OperandAccessMode::WRITE;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.instrDefinition->flags & IDF_OPERAND1_READWRITE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[0].access_mode = OperandAccessMode::READWRITE;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.operand[1].type != OperandType::NONE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.instrDefinition->flags & IDF_OPERAND2_WRITE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].access_mode = OperandAccessMode::WRITE;
|
2015-05-21 07:07:19 +08:00
|
|
|
|
} else if (info.instrDefinition->flags & IDF_OPERAND2_READWRITE)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].access_mode = OperandAccessMode::READWRITE;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Terminate loop
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::VEX:
|
|
|
|
|
if ((m_disassemblerMode == DisassemblerMode::M64BIT) ||
|
2015-05-21 07:07:19 +08:00
|
|
|
|
(((inputCurrent() >> 6) & 0x03) == 0x03))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
// Decode vex prefix
|
|
|
|
|
if (!decodeVex(info))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Update instruction info (error cases are checked by the @c decodeVex method)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
switch (info.vex_m_mmmm)
|
|
|
|
|
{
|
|
|
|
|
case 1:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.opcode_length = 1;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.opcode[0] = 0x0F;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.opcode_length = 2;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.opcode[0] = 0x0F;
|
|
|
|
|
info.opcode[1] = 0x38;
|
|
|
|
|
break;
|
|
|
|
|
case 3:
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.opcode_length = 2;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.opcode[0] = 0x0F;
|
|
|
|
|
info.opcode[1] = 0x3A;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// Set child node index for next iteration
|
|
|
|
|
index = info.vex_m_mmmm + (info.vex_pp << 2);
|
|
|
|
|
} else
|
|
|
|
|
{
|
|
|
|
|
index = 0;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::VEXW:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
assert(info.flags & IF_PREFIX_VEX);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
index = info.vex_w;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case OpcodeTreeNodeType::VEXL:
|
2015-05-21 07:07:19 +08:00
|
|
|
|
assert(info.flags & IF_PREFIX_VEX);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
index = info.vex_l;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
node = GetOpcodeTreeChild(node, index);
|
|
|
|
|
} while (nodeType != OpcodeTreeNodeType::INSTRUCTION_DEFINITION);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
InstructionDecoder::InstructionDecoder()
|
|
|
|
|
: m_input(nullptr)
|
|
|
|
|
, m_disassemblerMode(DisassemblerMode::M32BIT)
|
|
|
|
|
, m_preferredVendor(InstructionSetVendor::ANY)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
, m_instructionPointer(0)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
2014-10-27 21:10:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
InstructionDecoder::InstructionDecoder(BaseInput *input,
|
|
|
|
|
DisassemblerMode disassemblerMode, InstructionSetVendor preferredVendor,
|
2014-10-27 21:10:22 +08:00
|
|
|
|
uint64_t instructionPointer)
|
2015-05-16 11:05:17 +08:00
|
|
|
|
: m_input(input)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
, m_disassemblerMode(disassemblerMode)
|
2014-10-27 21:10:22 +08:00
|
|
|
|
, m_preferredVendor(preferredVendor)
|
|
|
|
|
, m_instructionPointer(instructionPointer)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
bool InstructionDecoder::decodeInstruction(InstructionInfo& info)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
// Clear instruction info
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
|
// Set disassembler mode flags
|
|
|
|
|
switch (m_disassemblerMode)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M16BIT:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.flags |= IF_DISASSEMBLER_MODE_16;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M32BIT:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.flags |= IF_DISASSEMBLER_MODE_32;
|
|
|
|
|
break;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
case DisassemblerMode::M64BIT:
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.flags |= IF_DISASSEMBLER_MODE_64;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Set instruction address
|
|
|
|
|
info.instrAddress = m_instructionPointer;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decode
|
|
|
|
|
if (!decodePrefixes(info) || !decodeOpcode(info))
|
|
|
|
|
{
|
|
|
|
|
goto DecodeError;
|
|
|
|
|
}
|
|
|
|
|
// SWAPGS is only valid in 64 bit mode
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.mnemonic == InstructionMnemonic::SWAPGS) &&
|
2015-05-16 11:05:17 +08:00
|
|
|
|
(m_disassemblerMode != DisassemblerMode::M64BIT))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
|
|
|
|
info.flags &= IF_ERROR_INVALID;
|
|
|
|
|
goto DecodeError;
|
|
|
|
|
}
|
|
|
|
|
// Handle aliases
|
2015-05-16 11:05:17 +08:00
|
|
|
|
if (info.mnemonic == InstructionMnemonic::XCHG)
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.operand[0].type == OperandType::REGISTER &&
|
|
|
|
|
info.operand[0].base == Register::AX &&
|
|
|
|
|
info.operand[1].type == OperandType::REGISTER &&
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].base == Register::AX) ||
|
2015-05-21 07:07:19 +08:00
|
|
|
|
(info.operand[0].type == OperandType::REGISTER &&
|
|
|
|
|
info.operand[0].base == Register::EAX &&
|
|
|
|
|
info.operand[1].type == OperandType::REGISTER &&
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.operand[1].base == Register::EAX))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.mnemonic = InstructionMnemonic::NOP;
|
|
|
|
|
info.operand[0].type = OperandType::NONE;
|
|
|
|
|
info.operand[1].type = OperandType::NONE;
|
|
|
|
|
info.operand[0].access_mode = OperandAccessMode::NA;
|
|
|
|
|
info.operand[1].access_mode = OperandAccessMode::NA;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if ((info.mnemonic == InstructionMnemonic::NOP) && (info.flags & IF_PREFIX_REP))
|
2014-10-25 05:11:16 +08:00
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.mnemonic = InstructionMnemonic::PAUSE;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.flags &= ~IF_PREFIX_REP;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
}
|
|
|
|
|
// Increment instruction pointer
|
|
|
|
|
m_instructionPointer += info.length;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Set instruction pointer
|
|
|
|
|
info.instrPointer = m_instructionPointer;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
DecodeError:
|
|
|
|
|
// Increment instruction pointer.
|
|
|
|
|
m_instructionPointer += 1;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
// Backup all error flags, the instruction length and the instruction address
|
2015-05-21 07:07:19 +08:00
|
|
|
|
uint32_t flags = info.flags & (IF_ERROR_MASK | 0x00000007);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
uint8_t length = info.length;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
uint8_t firstByte = info.data[0];
|
|
|
|
|
uint64_t instrAddress = info.instrAddress;
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Clear instruction info
|
|
|
|
|
memset(&info, 0, sizeof(info));
|
|
|
|
|
// Restore saved values
|
|
|
|
|
info.flags = flags;
|
|
|
|
|
info.length = length;
|
2014-10-27 21:10:22 +08:00
|
|
|
|
info.data[0] = firstByte;
|
|
|
|
|
info.instrAddress = instrAddress;
|
2015-05-16 11:05:17 +08:00
|
|
|
|
info.instrDefinition = Internal::GetInstructionDefinition(0);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
// Decrement the input position, if more than one byte was read from the input data
|
|
|
|
|
// source while decoding the invalid instruction.
|
|
|
|
|
if (info.length != 1)
|
|
|
|
|
{
|
2015-05-16 11:05:17 +08:00
|
|
|
|
m_input->setPosition(m_input->getPosition() - info.length + 1);
|
2014-10-25 05:11:16 +08:00
|
|
|
|
info.length = 1;
|
|
|
|
|
}
|
2015-05-16 11:05:17 +08:00
|
|
|
|
// Return with error, if the end of the input source was reached while decoding the
|
|
|
|
|
// invalid instruction
|
2015-05-21 07:07:19 +08:00
|
|
|
|
if (info.flags & IF_ERROR_END_OF_INPUT)
|
2015-05-16 11:05:17 +08:00
|
|
|
|
{
|
|
|
|
|
info.length = 0;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2014-10-25 05:11:16 +08:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-16 11:05:17 +08:00
|
|
|
|
/* ============================================================================================== */
|
|
|
|
|
|
|
|
|
|
}
|