mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 01:25:51 +00:00
798 lines
30 KiB
C
798 lines
30 KiB
C
/***************************************************************************************************
|
|
|
|
Zyan Disassembler Library (Zydis)
|
|
|
|
Original Author : Florian Bernd, Joel Hoener
|
|
|
|
* 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:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* 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.
|
|
|
|
***************************************************************************************************/
|
|
|
|
#include <Zydis/Internal/FormatterBase.h>
|
|
#include <Zydis/Utils.h>
|
|
|
|
/* ============================================================================================== */
|
|
/* Constants */
|
|
/* ============================================================================================== */
|
|
|
|
#include <Generated/FormatterStrings.inc>
|
|
|
|
static const ZydisShortString* const STR_PREF_REX[16] =
|
|
{
|
|
&STR_PREF_REX_40,
|
|
&STR_PREF_REX_41,
|
|
&STR_PREF_REX_42,
|
|
&STR_PREF_REX_43,
|
|
&STR_PREF_REX_44,
|
|
&STR_PREF_REX_45,
|
|
&STR_PREF_REX_46,
|
|
&STR_PREF_REX_47,
|
|
&STR_PREF_REX_48,
|
|
&STR_PREF_REX_49,
|
|
&STR_PREF_REX_4A,
|
|
&STR_PREF_REX_4B,
|
|
&STR_PREF_REX_4C,
|
|
&STR_PREF_REX_4D,
|
|
&STR_PREF_REX_4E,
|
|
&STR_PREF_REX_4F
|
|
};
|
|
|
|
static const ZydisPredefinedToken* const TOK_PREF_REX[16] =
|
|
{
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_40,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_41,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_42,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_43,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_44,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_45,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_46,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_47,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_48,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_49,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4A,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4B,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4C,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4D,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4E,
|
|
(const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4F
|
|
};
|
|
|
|
/* ============================================================================================== */
|
|
/* Helper functions */
|
|
/* ============================================================================================== */
|
|
|
|
ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
|
|
ZydisFormatterContext* context, const ZydisDecodedOperand* operand)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(context);
|
|
ZYAN_ASSERT(operand);
|
|
|
|
ZYAN_ASSERT(operand->type == ZYDIS_OPERAND_TYPE_MEMORY);
|
|
ZYAN_ASSERT((operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
|
|
(operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB));
|
|
|
|
if (formatter->force_memory_size)
|
|
{
|
|
return operand->size;
|
|
}
|
|
|
|
if (!context->operands)
|
|
{
|
|
// Single operand formatting. We can not derive the explicit size by using the other
|
|
// operands.
|
|
return 0;
|
|
}
|
|
|
|
switch (operand->id)
|
|
{
|
|
case 0:
|
|
if (context->instruction->operand_count_visible < 2)
|
|
{
|
|
return 0;
|
|
}
|
|
if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_UNUSED) ||
|
|
(context->operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE))
|
|
{
|
|
return context->operands[0].size;
|
|
}
|
|
if (context->operands[0].size != context->operands[1].size)
|
|
{
|
|
return context->operands[0].size;
|
|
}
|
|
if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
|
|
(context->operands[1].visibility == ZYDIS_OPERAND_VISIBILITY_IMPLICIT) &&
|
|
(context->operands[1].reg.value == ZYDIS_REGISTER_CL))
|
|
{
|
|
return context->operands[0].size;
|
|
}
|
|
break;
|
|
case 1:
|
|
case 2:
|
|
if (context->operands[operand->id - 1].size !=
|
|
context->operands[operand->id].size)
|
|
{
|
|
return context->operands[operand->id].size;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ============================================================================================== */
|
|
/* Formatter functions */
|
|
/* ============================================================================================== */
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Operands */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
return formatter->func_print_register(formatter, buffer, context, context->operand->reg.value);
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
|
|
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
|
|
context->operand->ptr.segment, 4, formatter->hex_force_leading_number);
|
|
ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
|
|
|
|
ZyanU8 padding;
|
|
switch (context->instruction->operand_width)
|
|
{
|
|
case 16:
|
|
padding = 4;
|
|
break;
|
|
case 32:
|
|
padding = 8;
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
|
|
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
|
|
context->operand->ptr.offset , padding, formatter->hex_force_leading_number);
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
// The immediate operand contains an address
|
|
if (context->operand->imm.is_relative)
|
|
{
|
|
const ZyanBool absolute = !formatter->force_relative_branches &&
|
|
(context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
|
|
if (absolute)
|
|
{
|
|
return formatter->func_print_address_abs(formatter, buffer, context);
|
|
}
|
|
return formatter->func_print_address_rel(formatter, buffer, context);
|
|
}
|
|
|
|
// The immediate operand contains an actual ordinal value
|
|
return formatter->func_print_imm(formatter, buffer, context);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Elemental tokens */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
ZyanU64 address;
|
|
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
|
|
context->runtime_address, &address));
|
|
ZyanU8 padding = (formatter->addr_padding_absolute ==
|
|
ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_absolute;
|
|
if ((formatter->addr_padding_absolute == ZYDIS_PADDING_AUTO) &&
|
|
(formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
|
|
{
|
|
switch (context->instruction->stack_width)
|
|
{
|
|
case 16:
|
|
padding = 4;
|
|
address = (ZyanU16)address;
|
|
break;
|
|
case 32:
|
|
padding = 8;
|
|
address = (ZyanU32)address;
|
|
break;
|
|
case 64:
|
|
padding = 16;
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_ABS);
|
|
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address, padding,
|
|
formatter->hex_force_leading_number);
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
ZyanU64 address;
|
|
ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
|
|
|
|
ZyanU8 padding = (formatter->addr_padding_relative ==
|
|
ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
|
|
if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
|
|
(formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
|
|
{
|
|
switch (context->instruction->stack_width)
|
|
{
|
|
case 16:
|
|
padding = 4;
|
|
address = (ZyanU16)address;
|
|
break;
|
|
case 32:
|
|
padding = 8;
|
|
address = (ZyanU32)address;
|
|
break;
|
|
case 64:
|
|
padding = 16;
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_REL);
|
|
switch (formatter->addr_signedness)
|
|
{
|
|
case ZYDIS_SIGNEDNESS_AUTO:
|
|
case ZYDIS_SIGNEDNESS_SIGNED:
|
|
ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address,
|
|
padding, formatter->hex_force_leading_number, ZYAN_TRUE);
|
|
break;
|
|
case ZYDIS_SIGNEDNESS_UNSIGNED:
|
|
ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ADD));
|
|
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address,
|
|
padding, formatter->hex_force_leading_number);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
|
|
|
|
const ZyanBool is_signed =
|
|
(formatter->imm_signedness == ZYDIS_SIGNEDNESS_SIGNED) ||
|
|
(formatter->imm_signedness == ZYDIS_SIGNEDNESS_AUTO && (context->operand->imm.is_signed));
|
|
if (is_signed && (context->operand->imm.value.s < 0))
|
|
{
|
|
ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->imm_base, &buffer->string,
|
|
context->operand->imm.value.s, formatter->imm_padding,
|
|
formatter->hex_force_leading_number, ZYAN_FALSE);
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
ZyanU64 value;
|
|
ZyanU8 padding = (formatter->imm_padding ==
|
|
ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->imm_padding;
|
|
switch (context->instruction->operand_width)
|
|
{
|
|
case 8:
|
|
if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
|
|
{
|
|
padding = 2;
|
|
}
|
|
value = (ZyanU8 )context->operand->imm.value.u;
|
|
break;
|
|
case 16:
|
|
if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
|
|
{
|
|
padding = 4;
|
|
}
|
|
value = (ZyanU16)context->operand->imm.value.u;
|
|
break;
|
|
case 32:
|
|
if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
|
|
{
|
|
padding = 8;
|
|
}
|
|
value = (ZyanU32)context->operand->imm.value.u;
|
|
break;
|
|
case 64:
|
|
if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
|
|
{
|
|
padding = 16;
|
|
}
|
|
value = (ZyanU64)context->operand->imm.value.u;
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->imm_base, &buffer->string, value, padding,
|
|
formatter->hex_force_leading_number);
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
/* Optional tokens */
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
ZyanBool printed_segment = ZYAN_FALSE;
|
|
switch (context->operand->mem.segment)
|
|
{
|
|
case ZYDIS_REGISTER_ES:
|
|
case ZYDIS_REGISTER_CS:
|
|
case ZYDIS_REGISTER_FS:
|
|
case ZYDIS_REGISTER_GS:
|
|
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
|
|
context->operand->mem.segment));
|
|
printed_segment = ZYAN_TRUE;
|
|
break;
|
|
case ZYDIS_REGISTER_SS:
|
|
if ((formatter->force_memory_segment) ||
|
|
(context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS))
|
|
{
|
|
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
|
|
context->operand->mem.segment));
|
|
printed_segment = ZYAN_TRUE;
|
|
}
|
|
break;
|
|
case ZYDIS_REGISTER_DS:
|
|
if ((formatter->force_memory_segment) ||
|
|
(context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_DS))
|
|
{
|
|
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
|
|
context->operand->mem.segment));
|
|
printed_segment = ZYAN_TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (printed_segment)
|
|
{
|
|
ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
|
|
}
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
if (formatter->detailed_prefixes)
|
|
{
|
|
for (ZyanU8 i = 0; i < context->instruction->raw.prefix_count; ++i)
|
|
{
|
|
const ZyanU8 value = context->instruction->raw.prefixes[i].value;
|
|
switch (context->instruction->raw.prefixes[i].type)
|
|
{
|
|
case ZYDIS_PREFIX_TYPE_IGNORED:
|
|
case ZYDIS_PREFIX_TYPE_MANDATORY:
|
|
{
|
|
if ((value & 0xF0) == 0x40)
|
|
{
|
|
if (buffer->is_token_list)
|
|
{
|
|
// TODO: Case
|
|
ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer,
|
|
TOK_PREF_REX[value & 0x0F]));
|
|
} else
|
|
{
|
|
ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string,
|
|
STR_PREF_REX[value & 0x0F], formatter->case_prefixes));
|
|
}
|
|
} else
|
|
{
|
|
switch (value)
|
|
{
|
|
case 0xF0:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
|
|
break;
|
|
case 0x2E:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_CS, formatter->case_prefixes);
|
|
break;
|
|
case 0x36:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_SS, formatter->case_prefixes);
|
|
break;
|
|
case 0x3E:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_DS, formatter->case_prefixes);
|
|
break;
|
|
case 0x26:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_ES, formatter->case_prefixes);
|
|
break;
|
|
case 0x64:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_FS, formatter->case_prefixes);
|
|
break;
|
|
case 0x65:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_GS, formatter->case_prefixes);
|
|
break;
|
|
default:
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_PREFIX);
|
|
ZYAN_CHECK(ZydisStringAppendHexU(&buffer->string, value, 0,
|
|
formatter->hex_force_leading_number, formatter->hex_uppercase,
|
|
ZYAN_NULL, ZYAN_NULL));
|
|
ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_WHITESPACE);
|
|
ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_WHITESPACE));
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case ZYDIS_PREFIX_TYPE_EFFECTIVE:
|
|
switch (value)
|
|
{
|
|
case 0xF0:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
|
|
break;
|
|
case 0xF2:
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
|
|
}
|
|
break;
|
|
case 0xF3:
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_NOTRACK, formatter->case_prefixes);
|
|
}
|
|
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
|
|
ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator)
|
|
{
|
|
ZYAN_ASSERT(formatter);
|
|
ZYAN_ASSERT(buffer);
|
|
ZYAN_ASSERT(context);
|
|
|
|
#if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
|
|
ZYAN_UNUSED(formatter);
|
|
ZYAN_UNUSED(buffer);
|
|
ZYAN_UNUSED(context);
|
|
#endif
|
|
|
|
switch (decorator)
|
|
{
|
|
case ZYDIS_DECORATOR_MASK:
|
|
{
|
|
#if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
|
|
if (context->instruction->avx.mask.reg != ZYDIS_REGISTER_K0)
|
|
{
|
|
if (buffer->is_token_list)
|
|
{
|
|
ZYDIS_BUFFER_APPEND(buffer, DECO_BEGIN);
|
|
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
|
|
context->instruction->avx.mask.reg));
|
|
ZYDIS_BUFFER_APPEND(buffer, DECO_END);
|
|
} else
|
|
{
|
|
ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_BEGIN));
|
|
ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
|
|
context->instruction->avx.mask.reg));
|
|
ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_END));
|
|
}
|
|
|
|
// Only print the zeroing decorator, if the instruction is not a "zeroing masking only"
|
|
// instruction (e.g. `vcmpsd`)
|
|
if ((context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_ZEROING ||
|
|
context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_CONTROL_ZEROING) &&
|
|
(context->instruction->raw.evex.z))
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_ZERO, formatter->case_decorators);
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
case ZYDIS_DECORATOR_BC:
|
|
#if !defined(ZYDIS_DISABLE_AVX512)
|
|
if (!context->instruction->avx.broadcast.is_static)
|
|
{
|
|
switch (context->instruction->avx.broadcast.mode)
|
|
{
|
|
case ZYDIS_BROADCAST_MODE_INVALID:
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_2:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO2, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_4:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO4, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_8:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO8, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO16, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_32:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO32, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_1_TO_64:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO64, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_4_TO_8:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO8, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_4_TO_16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO16, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_BROADCAST_MODE_8_TO_16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_8TO16, formatter->case_decorators);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
case ZYDIS_DECORATOR_RC:
|
|
#if !defined(ZYDIS_DISABLE_AVX512)
|
|
if (context->instruction->avx.has_sae)
|
|
{
|
|
switch (context->instruction->avx.rounding.mode)
|
|
{
|
|
case ZYDIS_ROUNDING_MODE_INVALID:
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RN:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN_SAE, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RD:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD_SAE, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RU:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU_SAE, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RZ:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ_SAE, formatter->case_decorators);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
} else
|
|
{
|
|
switch (context->instruction->avx.rounding.mode)
|
|
{
|
|
case ZYDIS_ROUNDING_MODE_INVALID:
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RN:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RD:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RU:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_ROUNDING_MODE_RZ:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ, formatter->case_decorators);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
case ZYDIS_DECORATOR_SAE:
|
|
#if !defined(ZYDIS_DISABLE_AVX512)
|
|
if (context->instruction->avx.has_sae && !context->instruction->avx.rounding.mode)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SAE, formatter->case_decorators);
|
|
}
|
|
#endif
|
|
break;
|
|
case ZYDIS_DECORATOR_SWIZZLE:
|
|
#if !defined(ZYDIS_DISABLE_KNC)
|
|
switch (context->instruction->avx.swizzle.mode)
|
|
{
|
|
case ZYDIS_SWIZZLE_MODE_INVALID:
|
|
case ZYDIS_SWIZZLE_MODE_DCBA:
|
|
// Nothing to do here
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_CDAB:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CDAB, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_BADC:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BADC, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_DACB:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DACB, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_AAAA:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_AAAA, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_BBBB:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BBBB, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_CCCC:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CCCC, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_SWIZZLE_MODE_DDDD:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DDDD, formatter->case_decorators);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
#endif
|
|
break;
|
|
case ZYDIS_DECORATOR_CONVERSION:
|
|
#if !defined(ZYDIS_DISABLE_KNC)
|
|
switch (context->instruction->avx.conversion.mode)
|
|
{
|
|
case ZYDIS_CONVERSION_MODE_INVALID:
|
|
break;
|
|
case ZYDIS_CONVERSION_MODE_FLOAT16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_FLOAT16, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_CONVERSION_MODE_SINT8:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT8, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_CONVERSION_MODE_UINT8:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT8, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_CONVERSION_MODE_SINT16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT16, formatter->case_decorators);
|
|
break;
|
|
case ZYDIS_CONVERSION_MODE_UINT16:
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT16, formatter->case_decorators);
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
#endif
|
|
break;
|
|
case ZYDIS_DECORATOR_EH:
|
|
#if !defined(ZYDIS_DISABLE_KNC)
|
|
if (context->instruction->avx.has_eviction_hint)
|
|
{
|
|
ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_EH, formatter->case_decorators);
|
|
}
|
|
#endif
|
|
break;
|
|
default:
|
|
return ZYAN_STATUS_INVALID_ARGUMENT;
|
|
}
|
|
|
|
return ZYAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------------------------- */
|
|
|
|
/* ============================================================================================== */
|