duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

FormatterBase.c (30214B)


      1 /***************************************************************************************************
      2 
      3   Zyan Disassembler Library (Zydis)
      4 
      5   Original Author : Florian Bernd, Joel Hoener
      6 
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in all
     15  * copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24 
     25 ***************************************************************************************************/
     26 
     27 #include <Zydis/Internal/FormatterBase.h>
     28 #include <Zydis/Utils.h>
     29 
     30 /* ============================================================================================== */
     31 /* Constants                                                                                      */
     32 /* ============================================================================================== */
     33 
     34 #include <Generated/FormatterStrings.inc>
     35 
     36 static const ZydisShortString* const STR_PREF_REX[16] =
     37 {
     38     &STR_PREF_REX_40,
     39     &STR_PREF_REX_41,
     40     &STR_PREF_REX_42,
     41     &STR_PREF_REX_43,
     42     &STR_PREF_REX_44,
     43     &STR_PREF_REX_45,
     44     &STR_PREF_REX_46,
     45     &STR_PREF_REX_47,
     46     &STR_PREF_REX_48,
     47     &STR_PREF_REX_49,
     48     &STR_PREF_REX_4A,
     49     &STR_PREF_REX_4B,
     50     &STR_PREF_REX_4C,
     51     &STR_PREF_REX_4D,
     52     &STR_PREF_REX_4E,
     53     &STR_PREF_REX_4F
     54 };
     55 
     56 static const ZydisPredefinedToken* const TOK_PREF_REX[16] =
     57 {
     58     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_40,
     59     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_41,
     60     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_42,
     61     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_43,
     62     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_44,
     63     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_45,
     64     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_46,
     65     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_47,
     66     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_48,
     67     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_49,
     68     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4A,
     69     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4B,
     70     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4C,
     71     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4D,
     72     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4E,
     73     (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4F
     74 };
     75 
     76 /* ============================================================================================== */
     77 /* Helper functions                                                                               */
     78 /* ============================================================================================== */
     79 
     80 ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
     81     ZydisFormatterContext* context, const ZydisDecodedOperand* operand)
     82 {
     83     ZYAN_ASSERT(formatter);
     84     ZYAN_ASSERT(context);
     85     ZYAN_ASSERT(operand);
     86 
     87     ZYAN_ASSERT(operand->type == ZYDIS_OPERAND_TYPE_MEMORY);
     88     ZYAN_ASSERT((operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
     89                 (operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB));
     90 
     91     if (formatter->force_memory_size)
     92     {
     93         return operand->size;
     94     }
     95 
     96     if (!context->operands)
     97     {
     98         // Single operand formatting. We can not derive the explicit size by using the other
     99         // operands.
    100         return 0;
    101     }
    102 
    103     switch (operand->id)
    104     {
    105     case 0:
    106         if (context->instruction->operand_count_visible < 2)
    107         {
    108             return 0;
    109         }
    110         if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_UNUSED) ||
    111             (context->operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE))
    112         {
    113             return context->operands[0].size;
    114         }
    115         if (context->operands[0].size != context->operands[1].size)
    116         {
    117             return context->operands[0].size;
    118         }
    119         if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
    120             (context->operands[1].visibility == ZYDIS_OPERAND_VISIBILITY_IMPLICIT) &&
    121             (context->operands[1].reg.value == ZYDIS_REGISTER_CL))
    122         {
    123             return context->operands[0].size;
    124         }
    125         break;
    126     case 1:
    127     case 2:
    128         if (context->operands[operand->id - 1].size !=
    129             context->operands[operand->id].size)
    130         {
    131             return context->operands[operand->id].size;
    132         }
    133         break;
    134     default:
    135         break;
    136     }
    137 
    138     return 0;
    139 }
    140 
    141 /* ============================================================================================== */
    142 /* Formatter functions                                                                            */
    143 /* ============================================================================================== */
    144 
    145 /* ---------------------------------------------------------------------------------------------- */
    146 /* Operands                                                                                       */
    147 /* ---------------------------------------------------------------------------------------------- */
    148 
    149 ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
    150     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    151 {
    152     ZYAN_ASSERT(formatter);
    153     ZYAN_ASSERT(buffer);
    154     ZYAN_ASSERT(context);
    155 
    156     return formatter->func_print_register(formatter, buffer, context, context->operand->reg.value);
    157 }
    158 
    159 ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
    160     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    161 {
    162     ZYAN_ASSERT(formatter);
    163     ZYAN_ASSERT(buffer);
    164     ZYAN_ASSERT(context);
    165 
    166     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
    167     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
    168         context->operand->ptr.segment, 4, formatter->hex_force_leading_number);
    169     ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
    170 
    171     ZyanU8 padding;
    172     switch (context->instruction->operand_width)
    173     {
    174     case 16:
    175         padding = 4;
    176         break;
    177     case 32:
    178         padding = 8;
    179         break;
    180     default:
    181         return ZYAN_STATUS_INVALID_ARGUMENT;
    182     }
    183 
    184     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
    185     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
    186         context->operand->ptr.offset , padding, formatter->hex_force_leading_number);
    187 
    188     return ZYAN_STATUS_SUCCESS;
    189 }
    190 
    191 ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
    192     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    193 {
    194     ZYAN_ASSERT(formatter);
    195     ZYAN_ASSERT(buffer);
    196     ZYAN_ASSERT(context);
    197 
    198     // The immediate operand contains an address
    199     if (context->operand->imm.is_relative)
    200     {
    201         const ZyanBool absolute = !formatter->force_relative_branches &&
    202             (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
    203         if (absolute)
    204         {
    205             return formatter->func_print_address_abs(formatter, buffer, context);
    206         }
    207         return formatter->func_print_address_rel(formatter, buffer, context);
    208     }
    209 
    210     // The immediate operand contains an actual ordinal value
    211     return formatter->func_print_imm(formatter, buffer, context);
    212 }
    213 
    214 /* ---------------------------------------------------------------------------------------------- */
    215 /* Elemental tokens                                                                               */
    216 /* ---------------------------------------------------------------------------------------------- */
    217 
    218 ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
    219     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    220 {
    221     ZYAN_ASSERT(formatter);
    222     ZYAN_ASSERT(buffer);
    223     ZYAN_ASSERT(context);
    224 
    225     ZyanU64 address;
    226     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
    227         context->runtime_address, &address));
    228     ZyanU8 padding = (formatter->addr_padding_absolute ==
    229         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_absolute;
    230     if ((formatter->addr_padding_absolute == ZYDIS_PADDING_AUTO) &&
    231         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
    232     {
    233         switch (context->instruction->stack_width)
    234         {
    235         case 16:
    236             padding =  4;
    237             address = (ZyanU16)address;
    238             break;
    239         case 32:
    240             padding =  8;
    241             address = (ZyanU32)address;
    242             break;
    243         case 64:
    244             padding = 16;
    245             break;
    246         default:
    247             return ZYAN_STATUS_INVALID_ARGUMENT;
    248         }
    249     }
    250 
    251     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_ABS);
    252     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address, padding,
    253         formatter->hex_force_leading_number);
    254 
    255     return ZYAN_STATUS_SUCCESS;
    256 }
    257 
    258 ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
    259     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    260 {
    261     ZYAN_ASSERT(formatter);
    262     ZYAN_ASSERT(buffer);
    263     ZYAN_ASSERT(context);
    264 
    265     ZyanU64 address;
    266     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
    267 
    268     ZyanU8 padding = (formatter->addr_padding_relative ==
    269         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
    270     if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
    271         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
    272     {
    273         switch (context->instruction->stack_width)
    274         {
    275         case 16:
    276             padding =  4;
    277             address = (ZyanU16)address;
    278             break;
    279         case 32:
    280             padding =  8;
    281             address = (ZyanU32)address;
    282             break;
    283         case 64:
    284             padding = 16;
    285             break;
    286         default:
    287             return ZYAN_STATUS_INVALID_ARGUMENT;
    288         }
    289     }
    290 
    291     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_REL);
    292     switch (formatter->addr_signedness)
    293     {
    294     case ZYDIS_SIGNEDNESS_AUTO:
    295     case ZYDIS_SIGNEDNESS_SIGNED:
    296         ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address,
    297             padding, formatter->hex_force_leading_number, ZYAN_TRUE);
    298         break;
    299     case ZYDIS_SIGNEDNESS_UNSIGNED:
    300         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ADD));
    301         ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address,
    302             padding, formatter->hex_force_leading_number);
    303         break;
    304     default:
    305         return ZYAN_STATUS_INVALID_ARGUMENT;
    306     }
    307 
    308     return ZYAN_STATUS_SUCCESS;
    309 }
    310 
    311 ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
    312     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    313 {
    314     ZYAN_ASSERT(formatter);
    315     ZYAN_ASSERT(buffer);
    316     ZYAN_ASSERT(context);
    317 
    318     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
    319 
    320     const ZyanBool is_signed =
    321         (formatter->imm_signedness == ZYDIS_SIGNEDNESS_SIGNED) ||
    322         (formatter->imm_signedness == ZYDIS_SIGNEDNESS_AUTO && (context->operand->imm.is_signed));
    323     if (is_signed && (context->operand->imm.value.s < 0))
    324     {
    325         ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->imm_base, &buffer->string,
    326             context->operand->imm.value.s, formatter->imm_padding,
    327             formatter->hex_force_leading_number, ZYAN_FALSE);
    328         return ZYAN_STATUS_SUCCESS;
    329     }
    330     ZyanU64 value;
    331     ZyanU8 padding = (formatter->imm_padding ==
    332         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->imm_padding;
    333     switch (context->instruction->operand_width)
    334     {
    335     case 8:
    336         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
    337         {
    338             padding =  2;
    339         }
    340         value = (ZyanU8 )context->operand->imm.value.u;
    341         break;
    342     case 16:
    343         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
    344         {
    345             padding =  4;
    346         }
    347         value = (ZyanU16)context->operand->imm.value.u;
    348         break;
    349     case 32:
    350         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
    351         {
    352             padding =  8;
    353         }
    354         value = (ZyanU32)context->operand->imm.value.u;
    355         break;
    356     case 64:
    357         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
    358         {
    359             padding = 16;
    360         }
    361         value = (ZyanU64)context->operand->imm.value.u;
    362         break;
    363     default:
    364         return ZYAN_STATUS_INVALID_ARGUMENT;
    365     }
    366     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->imm_base, &buffer->string, value, padding,
    367         formatter->hex_force_leading_number);
    368 
    369     return ZYAN_STATUS_SUCCESS;
    370 }
    371 
    372 /* ---------------------------------------------------------------------------------------------- */
    373 /* Optional tokens                                                                                */
    374 /* ---------------------------------------------------------------------------------------------- */
    375 
    376 ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
    377     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    378 {
    379     ZYAN_ASSERT(formatter);
    380     ZYAN_ASSERT(buffer);
    381     ZYAN_ASSERT(context);
    382 
    383     ZyanBool printed_segment = ZYAN_FALSE;
    384     switch (context->operand->mem.segment)
    385     {
    386     case ZYDIS_REGISTER_ES:
    387     case ZYDIS_REGISTER_CS:
    388     case ZYDIS_REGISTER_FS:
    389     case ZYDIS_REGISTER_GS:
    390         ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    391             context->operand->mem.segment));
    392         printed_segment = ZYAN_TRUE;
    393         break;
    394     case ZYDIS_REGISTER_SS:
    395         if ((formatter->force_memory_segment) ||
    396             (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS))
    397         {
    398             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    399                 context->operand->mem.segment));
    400             printed_segment = ZYAN_TRUE;
    401         }
    402         break;
    403     case ZYDIS_REGISTER_DS:
    404         if ((formatter->force_memory_segment) ||
    405             (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_DS))
    406         {
    407             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    408                 context->operand->mem.segment));
    409             printed_segment = ZYAN_TRUE;
    410         }
    411         break;
    412     default:
    413         break;
    414     }
    415     if (printed_segment)
    416     {
    417         ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
    418     }
    419 
    420     return ZYAN_STATUS_SUCCESS;
    421 }
    422 
    423 ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
    424     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    425 {
    426     ZYAN_ASSERT(formatter);
    427     ZYAN_ASSERT(buffer);
    428     ZYAN_ASSERT(context);
    429 
    430     if (formatter->detailed_prefixes)
    431     {
    432         for (ZyanU8 i = 0; i < context->instruction->raw.prefix_count; ++i)
    433         {
    434             const ZyanU8 value = context->instruction->raw.prefixes[i].value;
    435             switch (context->instruction->raw.prefixes[i].type)
    436             {
    437             case ZYDIS_PREFIX_TYPE_IGNORED:
    438             case ZYDIS_PREFIX_TYPE_MANDATORY:
    439             {
    440                 if ((value & 0xF0) == 0x40)
    441                 {
    442                     if (buffer->is_token_list)
    443                     {
    444                         // TODO: Case
    445                         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer,
    446                             TOK_PREF_REX[value & 0x0F]));
    447                     } else
    448                     {
    449                         ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string,
    450                             STR_PREF_REX[value & 0x0F], formatter->case_prefixes));
    451                     }
    452                 } else
    453                 {
    454                     switch (value)
    455                     {
    456                     case 0xF0:
    457                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
    458                         break;
    459                     case 0x2E:
    460                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_CS, formatter->case_prefixes);
    461                         break;
    462                     case 0x36:
    463                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_SS, formatter->case_prefixes);
    464                         break;
    465                     case 0x3E:
    466                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_DS, formatter->case_prefixes);
    467                         break;
    468                     case 0x26:
    469                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_ES, formatter->case_prefixes);
    470                         break;
    471                     case 0x64:
    472                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_FS, formatter->case_prefixes);
    473                         break;
    474                     case 0x65:
    475                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_GS, formatter->case_prefixes);
    476                         break;
    477                     default:
    478                         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_PREFIX);
    479                         ZYAN_CHECK(ZydisStringAppendHexU(&buffer->string, value, 0,
    480                             formatter->hex_force_leading_number, formatter->hex_uppercase,
    481                             ZYAN_NULL, ZYAN_NULL));
    482                         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_WHITESPACE);
    483                         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_WHITESPACE));
    484                         break;
    485                     }
    486                 }
    487                 break;
    488             }
    489             case ZYDIS_PREFIX_TYPE_EFFECTIVE:
    490                 switch (value)
    491                 {
    492                 case 0xF0:
    493                     ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
    494                     break;
    495                 case 0xF2:
    496                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
    497                     {
    498                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
    499                     }
    500                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
    501                     {
    502                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
    503                     }
    504 
    505                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
    506                     {
    507                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
    508                     }
    509                     break;
    510                 case 0xF3:
    511                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
    512                     {
    513                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
    514                     }
    515                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
    516                     {
    517                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
    518                     }
    519                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
    520                     {
    521                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
    522                     }
    523                     break;
    524                 default:
    525                     break;
    526                 }
    527                 break;
    528             default:
    529                 return ZYAN_STATUS_INVALID_ARGUMENT;
    530             }
    531         }
    532         return ZYAN_STATUS_SUCCESS;
    533     }
    534 
    535     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
    536     {
    537         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
    538     }
    539     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
    540     {
    541         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
    542     }
    543 
    544     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
    545     {
    546         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
    547     }
    548 
    549     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
    550     {
    551         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
    552     }
    553 
    554     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK)
    555     {
    556         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_NOTRACK, formatter->case_prefixes);
    557     }
    558 
    559     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
    560     {
    561         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
    562         return ZYAN_STATUS_SUCCESS;
    563     }
    564     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
    565     {
    566         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
    567         return ZYAN_STATUS_SUCCESS;
    568     }
    569     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
    570     {
    571         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
    572         return ZYAN_STATUS_SUCCESS;
    573     }
    574 
    575     return ZYAN_STATUS_SUCCESS;
    576 }
    577 
    578 ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
    579     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator)
    580 {
    581     ZYAN_ASSERT(formatter);
    582     ZYAN_ASSERT(buffer);
    583     ZYAN_ASSERT(context);
    584 
    585 #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
    586     ZYAN_UNUSED(formatter);
    587     ZYAN_UNUSED(buffer);
    588     ZYAN_UNUSED(context);
    589 #endif
    590 
    591     switch (decorator)
    592     {
    593     case ZYDIS_DECORATOR_MASK:
    594     {
    595 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
    596         if (context->instruction->avx.mask.reg != ZYDIS_REGISTER_K0)
    597         {
    598             if (buffer->is_token_list)
    599             {
    600                 ZYDIS_BUFFER_APPEND(buffer, DECO_BEGIN);
    601                 ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    602                     context->instruction->avx.mask.reg));
    603                 ZYDIS_BUFFER_APPEND(buffer, DECO_END);
    604             } else
    605             {
    606                 ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_BEGIN));
    607                 ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    608                     context->instruction->avx.mask.reg));
    609                 ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_END));
    610             }
    611 
    612             // Only print the zeroing decorator, if the instruction is not a "zeroing masking only"
    613             // instruction (e.g. `vcmpsd`)
    614             if ((context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_ZEROING ||
    615                  context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_CONTROL_ZEROING) &&
    616                 (context->instruction->raw.evex.z))
    617             {
    618                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_ZERO, formatter->case_decorators);
    619             }
    620         }
    621 #endif
    622         break;
    623     }
    624     case ZYDIS_DECORATOR_BC:
    625 #if !defined(ZYDIS_DISABLE_AVX512)
    626         if (!context->instruction->avx.broadcast.is_static)
    627         {
    628             switch (context->instruction->avx.broadcast.mode)
    629             {
    630             case ZYDIS_BROADCAST_MODE_INVALID:
    631                 break;
    632             case ZYDIS_BROADCAST_MODE_1_TO_2:
    633                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO2, formatter->case_decorators);
    634                 break;
    635             case ZYDIS_BROADCAST_MODE_1_TO_4:
    636                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO4, formatter->case_decorators);
    637                 break;
    638             case ZYDIS_BROADCAST_MODE_1_TO_8:
    639                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO8, formatter->case_decorators);
    640                 break;
    641             case ZYDIS_BROADCAST_MODE_1_TO_16:
    642                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO16, formatter->case_decorators);
    643                 break;
    644             case ZYDIS_BROADCAST_MODE_1_TO_32:
    645                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO32, formatter->case_decorators);
    646                 break;
    647             case ZYDIS_BROADCAST_MODE_1_TO_64:
    648                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO64, formatter->case_decorators);
    649                 break;
    650             case ZYDIS_BROADCAST_MODE_4_TO_8:
    651                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO8, formatter->case_decorators);
    652                 break;
    653             case ZYDIS_BROADCAST_MODE_4_TO_16:
    654                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO16, formatter->case_decorators);
    655                 break;
    656             case ZYDIS_BROADCAST_MODE_8_TO_16:
    657                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_8TO16, formatter->case_decorators);
    658                 break;
    659             default:
    660                 return ZYAN_STATUS_INVALID_ARGUMENT;
    661             }
    662         }
    663 #endif
    664         break;
    665     case ZYDIS_DECORATOR_RC:
    666 #if !defined(ZYDIS_DISABLE_AVX512)
    667         if (context->instruction->avx.has_sae)
    668         {
    669             switch (context->instruction->avx.rounding.mode)
    670             {
    671             case ZYDIS_ROUNDING_MODE_INVALID:
    672                 break;
    673             case ZYDIS_ROUNDING_MODE_RN:
    674                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN_SAE, formatter->case_decorators);
    675                 break;
    676             case ZYDIS_ROUNDING_MODE_RD:
    677                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD_SAE, formatter->case_decorators);
    678                 break;
    679             case ZYDIS_ROUNDING_MODE_RU:
    680                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU_SAE, formatter->case_decorators);
    681                 break;
    682             case ZYDIS_ROUNDING_MODE_RZ:
    683                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ_SAE, formatter->case_decorators);
    684                 break;
    685             default:
    686                 return ZYAN_STATUS_INVALID_ARGUMENT;
    687             }
    688         } else
    689         {
    690             switch (context->instruction->avx.rounding.mode)
    691             {
    692             case ZYDIS_ROUNDING_MODE_INVALID:
    693                 break;
    694             case ZYDIS_ROUNDING_MODE_RN:
    695                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN, formatter->case_decorators);
    696                 break;
    697             case ZYDIS_ROUNDING_MODE_RD:
    698                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD, formatter->case_decorators);
    699                 break;
    700             case ZYDIS_ROUNDING_MODE_RU:
    701                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU, formatter->case_decorators);
    702                 break;
    703             case ZYDIS_ROUNDING_MODE_RZ:
    704                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ, formatter->case_decorators);
    705                 break;
    706             default:
    707                 return ZYAN_STATUS_INVALID_ARGUMENT;
    708             }
    709         }
    710 #endif
    711         break;
    712     case ZYDIS_DECORATOR_SAE:
    713 #if !defined(ZYDIS_DISABLE_AVX512)
    714         if (context->instruction->avx.has_sae && !context->instruction->avx.rounding.mode)
    715         {
    716             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SAE, formatter->case_decorators);
    717         }
    718 #endif
    719         break;
    720     case ZYDIS_DECORATOR_SWIZZLE:
    721 #if !defined(ZYDIS_DISABLE_KNC)
    722         switch (context->instruction->avx.swizzle.mode)
    723         {
    724         case ZYDIS_SWIZZLE_MODE_INVALID:
    725         case ZYDIS_SWIZZLE_MODE_DCBA:
    726             // Nothing to do here
    727             break;
    728         case ZYDIS_SWIZZLE_MODE_CDAB:
    729             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CDAB, formatter->case_decorators);
    730             break;
    731         case ZYDIS_SWIZZLE_MODE_BADC:
    732             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BADC, formatter->case_decorators);
    733             break;
    734         case ZYDIS_SWIZZLE_MODE_DACB:
    735             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DACB, formatter->case_decorators);
    736             break;
    737         case ZYDIS_SWIZZLE_MODE_AAAA:
    738             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_AAAA, formatter->case_decorators);
    739             break;
    740         case ZYDIS_SWIZZLE_MODE_BBBB:
    741             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BBBB, formatter->case_decorators);
    742             break;
    743         case ZYDIS_SWIZZLE_MODE_CCCC:
    744             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CCCC, formatter->case_decorators);
    745             break;
    746         case ZYDIS_SWIZZLE_MODE_DDDD:
    747             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DDDD, formatter->case_decorators);
    748             break;
    749         default:
    750             return ZYAN_STATUS_INVALID_ARGUMENT;
    751         }
    752 #endif
    753         break;
    754     case ZYDIS_DECORATOR_CONVERSION:
    755 #if !defined(ZYDIS_DISABLE_KNC)
    756         switch (context->instruction->avx.conversion.mode)
    757         {
    758         case ZYDIS_CONVERSION_MODE_INVALID:
    759             break;
    760         case ZYDIS_CONVERSION_MODE_FLOAT16:
    761             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_FLOAT16, formatter->case_decorators);
    762             break;
    763         case ZYDIS_CONVERSION_MODE_SINT8:
    764             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT8, formatter->case_decorators);
    765             break;
    766         case ZYDIS_CONVERSION_MODE_UINT8:
    767             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT8, formatter->case_decorators);
    768             break;
    769         case ZYDIS_CONVERSION_MODE_SINT16:
    770             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT16, formatter->case_decorators);
    771             break;
    772         case ZYDIS_CONVERSION_MODE_UINT16:
    773             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT16, formatter->case_decorators);
    774             break;
    775         default:
    776             return ZYAN_STATUS_INVALID_ARGUMENT;
    777         }
    778 #endif
    779         break;
    780     case ZYDIS_DECORATOR_EH:
    781 #if !defined(ZYDIS_DISABLE_KNC)
    782         if (context->instruction->avx.has_eviction_hint)
    783         {
    784             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_EH, formatter->case_decorators);
    785         }
    786 #endif
    787         break;
    788     default:
    789         return ZYAN_STATUS_INVALID_ARGUMENT;
    790     }
    791 
    792     return ZYAN_STATUS_SUCCESS;
    793 }
    794 
    795 /* ---------------------------------------------------------------------------------------------- */
    796 
    797 /* ============================================================================================== */