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

FormatterIntel.c (17999B)


      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/FormatterIntel.h>
     28 #include <Zydis/Utils.h>
     29 #include <Zycore/Format.h>
     30 
     31 /* ============================================================================================== */
     32 /* Constants                                                                                      */
     33 /* ============================================================================================== */
     34 
     35 #include <Generated/FormatterStrings.inc>
     36 
     37 /* ============================================================================================== */
     38 /* Formatter functions                                                                            */
     39 /* ============================================================================================== */
     40 
     41 /* ---------------------------------------------------------------------------------------------- */
     42 /* Intel                                                                                          */
     43 /* ---------------------------------------------------------------------------------------------- */
     44 
     45 ZyanStatus ZydisFormatterIntelFormatInstruction(const ZydisFormatter* formatter,
     46     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
     47 {
     48     ZYAN_ASSERT(formatter);
     49     ZYAN_ASSERT(buffer);
     50     ZYAN_ASSERT(context);
     51     ZYAN_ASSERT(context->instruction);
     52     ZYAN_ASSERT(context->operands);
     53 
     54     ZYAN_CHECK(formatter->func_print_prefixes(formatter, buffer, context));
     55     ZYAN_CHECK(formatter->func_print_mnemonic(formatter, buffer, context));
     56 
     57     ZyanUPointer state_mnemonic;
     58     ZYDIS_BUFFER_REMEMBER(buffer, state_mnemonic);
     59     for (ZyanU8 i = 0; i < context->instruction->operand_count_visible; ++i)
     60     {
     61         const ZydisDecodedOperand* const operand = &context->operands[i];
     62 
     63         // Print embedded-mask registers as decorator instead of a regular operand
     64         if ((i == 1) && (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) &&
     65             (operand->encoding == ZYDIS_OPERAND_ENCODING_MASK))
     66         {
     67             continue;
     68         }
     69 
     70         ZyanUPointer buffer_state;
     71         ZYDIS_BUFFER_REMEMBER(buffer, buffer_state);
     72 
     73         if (buffer_state != state_mnemonic)
     74         {
     75             ZYDIS_BUFFER_APPEND(buffer, DELIM_OPERAND);
     76         } else
     77         {
     78             ZYDIS_BUFFER_APPEND(buffer, DELIM_MNEMONIC);
     79         }
     80 
     81         // Set current operand
     82         context->operand = operand;
     83 
     84         ZyanStatus status;
     85         if (formatter->func_pre_operand)
     86         {
     87             status = formatter->func_pre_operand(formatter, buffer, context);
     88             if (status == ZYDIS_STATUS_SKIP_TOKEN)
     89             {
     90                 ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
     91                 continue;
     92             }
     93             if (!ZYAN_SUCCESS(status))
     94             {
     95                 return status;
     96             }
     97         }
     98 
     99         switch (operand->type)
    100         {
    101         case ZYDIS_OPERAND_TYPE_REGISTER:
    102             status = formatter->func_format_operand_reg(formatter, buffer, context);
    103             break;
    104         case ZYDIS_OPERAND_TYPE_MEMORY:
    105             status = formatter->func_format_operand_mem(formatter, buffer, context);
    106             break;
    107         case ZYDIS_OPERAND_TYPE_POINTER:
    108             status = formatter->func_format_operand_ptr(formatter, buffer, context);
    109             break;
    110         case ZYDIS_OPERAND_TYPE_IMMEDIATE:
    111             status = formatter->func_format_operand_imm(formatter, buffer, context);
    112             break;
    113         default:
    114             return ZYAN_STATUS_INVALID_ARGUMENT;
    115         }
    116         if (status == ZYDIS_STATUS_SKIP_TOKEN)
    117         {
    118             ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
    119             continue;
    120         }
    121         if (!ZYAN_SUCCESS(status))
    122         {
    123             return status;
    124         }
    125 
    126         if (formatter->func_post_operand)
    127         {
    128             status = formatter->func_post_operand(formatter, buffer, context);
    129             if (status == ZYDIS_STATUS_SKIP_TOKEN)
    130             {
    131                 ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
    132                 continue;
    133             }
    134             if (ZYAN_SUCCESS(status))
    135             {
    136                 return status;
    137             }
    138         }
    139 
    140 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
    141         if ((context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
    142             (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
    143         {
    144             if  ((i == 0) &&
    145                  (context->instruction->operand_count_visible > 1) &&
    146                  (context->operands[i + 1].encoding == ZYDIS_OPERAND_ENCODING_MASK))
    147             {
    148                 ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    149                     ZYDIS_DECORATOR_MASK));
    150             }
    151             if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY)
    152             {
    153                 ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    154                     ZYDIS_DECORATOR_BC));
    155                 if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
    156                 {
    157                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    158                         ZYDIS_DECORATOR_CONVERSION));
    159                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    160                         ZYDIS_DECORATOR_EH));
    161                 }
    162             } else
    163             {
    164                 ZyanBool decorate_operand;
    165                 if (i == (context->instruction->operand_count_visible - 1))
    166                 {
    167                     decorate_operand = operand->type != ZYDIS_OPERAND_TYPE_IMMEDIATE;
    168                 }
    169                 else
    170                 {
    171                     decorate_operand =
    172                         (context->instruction->operand_count_visible > (i + 1)) &&
    173                         ((context->operands[i + 1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) ||
    174                         (context->operands[i + 1].visibility == ZYDIS_OPERAND_VISIBILITY_HIDDEN));
    175                 }
    176                 if (decorate_operand)
    177                 {
    178                     if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
    179                     {
    180                         ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    181                             ZYDIS_DECORATOR_SWIZZLE));
    182                     }
    183                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    184                         ZYDIS_DECORATOR_RC));
    185                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
    186                         ZYDIS_DECORATOR_SAE));
    187                 }
    188             }
    189         }
    190 #endif
    191     }
    192 
    193     return ZYAN_STATUS_SUCCESS;
    194 }
    195 
    196 ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,
    197     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    198 {
    199     ZYAN_ASSERT(formatter);
    200     ZYAN_ASSERT(buffer);
    201     ZYAN_ASSERT(context);
    202 
    203     if ((context->operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
    204         (context->operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB))
    205     {
    206         ZYAN_CHECK(formatter->func_print_typecast(formatter, buffer, context));
    207     }
    208     ZYAN_CHECK(formatter->func_print_segment(formatter, buffer, context));
    209 
    210     ZYDIS_BUFFER_APPEND(buffer, MEMORY_BEGIN_INTEL);
    211 
    212     const ZyanBool absolute = !formatter->force_relative_riprel &&
    213         (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
    214     if (absolute && context->operand->mem.disp.has_displacement &&
    215         (context->operand->mem.index == ZYDIS_REGISTER_NONE) &&
    216        ((context->operand->mem.base  == ZYDIS_REGISTER_NONE) ||
    217         (context->operand->mem.base  == ZYDIS_REGISTER_EIP ) ||
    218         (context->operand->mem.base  == ZYDIS_REGISTER_RIP )))
    219     {
    220         // EIP/RIP-relative or absolute-displacement address operand
    221         ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
    222     } else
    223     {
    224         const ZyanBool should_print_reg = context->operand->mem.base != ZYDIS_REGISTER_NONE;
    225         const ZyanBool should_print_idx = context->operand->mem.index != ZYDIS_REGISTER_NONE;
    226         const ZyanBool neither_reg_nor_idx = !should_print_reg && !should_print_idx;
    227 
    228         // Regular memory operand
    229         if (should_print_reg)
    230         {
    231             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    232                 context->operand->mem.base));
    233         }
    234         if (should_print_idx)
    235         {
    236             if (context->operand->mem.base != ZYDIS_REGISTER_NONE)
    237             {
    238                 ZYDIS_BUFFER_APPEND(buffer, ADD);
    239             }
    240             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
    241                 context->operand->mem.index));
    242             if (context->operand->mem.scale &&
    243                 (context->operand->mem.type != ZYDIS_MEMOP_TYPE_MIB) &&
    244                 ((context->operand->mem.scale > 1) || formatter->force_memory_scale))
    245             {
    246                 ZYDIS_BUFFER_APPEND(buffer, MUL);
    247                 ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
    248                 ZYAN_CHECK(ZydisStringAppendDecU(&buffer->string, context->operand->mem.scale, 0,
    249                     ZYAN_NULL, ZYAN_NULL));
    250             }
    251         }
    252         if (neither_reg_nor_idx)
    253         {
    254             ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
    255         } else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value)
    256         {
    257             ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context));
    258         }
    259     }
    260 
    261     ZYDIS_BUFFER_APPEND(buffer, MEMORY_END_INTEL);
    262     return ZYAN_STATUS_SUCCESS;
    263 }
    264 
    265 ZyanStatus ZydisFormatterIntelPrintMnemonic(const ZydisFormatter* formatter,
    266     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    267 {
    268     ZYAN_ASSERT(formatter);
    269     ZYAN_ASSERT(buffer);
    270     ZYAN_ASSERT(context);
    271 
    272     const ZydisShortString* mnemonic = ZydisMnemonicGetStringWrapped(
    273         context->instruction->mnemonic);
    274     if (!mnemonic)
    275     {
    276         ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_MNEMONIC, formatter->case_mnemonic);
    277         return ZYAN_STATUS_SUCCESS;
    278     }
    279 
    280     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_MNEMONIC);
    281     ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, mnemonic, formatter->case_mnemonic));
    282     if (context->instruction->meta.branch_type == ZYDIS_BRANCH_TYPE_FAR)
    283     {
    284         return ZydisStringAppendShortCase(&buffer->string, &STR_FAR, formatter->case_mnemonic);
    285     }
    286     if (formatter->print_branch_size)
    287     {
    288         switch (context->instruction->meta.branch_type)
    289         {
    290         case ZYDIS_BRANCH_TYPE_NONE:
    291             break;
    292         case ZYDIS_BRANCH_TYPE_SHORT:
    293             return ZydisStringAppendShortCase(&buffer->string, &STR_SHORT,
    294                 formatter->case_mnemonic);
    295         case ZYDIS_BRANCH_TYPE_NEAR:
    296             return ZydisStringAppendShortCase(&buffer->string, &STR_NEAR,
    297                 formatter->case_mnemonic);
    298         default:
    299             return ZYAN_STATUS_INVALID_ARGUMENT;
    300         }
    301     }
    302 
    303     return ZYAN_STATUS_SUCCESS;
    304 }
    305 
    306 ZyanStatus ZydisFormatterIntelPrintRegister(const ZydisFormatter* formatter,
    307     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg)
    308 {
    309     ZYAN_UNUSED(context);
    310 
    311     ZYAN_ASSERT(formatter);
    312     ZYAN_ASSERT(buffer);
    313     ZYAN_ASSERT(context);
    314 
    315     const ZydisShortString* str = ZydisRegisterGetStringWrapped(reg);
    316     if (!str)
    317     {
    318         ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_REG, formatter->case_registers);
    319         return ZYAN_STATUS_SUCCESS;
    320     }
    321 
    322     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_REGISTER);
    323     return ZydisStringAppendShortCase(&buffer->string, str, formatter->case_registers);
    324 }
    325 
    326 ZyanStatus ZydisFormatterIntelPrintDISP(const ZydisFormatter* formatter,
    327     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    328 {
    329     ZYAN_ASSERT(formatter);
    330     ZYAN_ASSERT(buffer);
    331     ZYAN_ASSERT(context);
    332 
    333     switch (formatter->disp_signedness)
    334     {
    335     case ZYDIS_SIGNEDNESS_AUTO:
    336     case ZYDIS_SIGNEDNESS_SIGNED:
    337         if (context->operand->mem.disp.value < 0)
    338         {
    339             if ((context->operand->mem.base  != ZYDIS_REGISTER_NONE) ||
    340                 (context->operand->mem.index != ZYDIS_REGISTER_NONE))
    341             {
    342                 ZYDIS_BUFFER_APPEND(buffer, SUB);
    343             }
    344             ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
    345             ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
    346                 ZyanAbsI64(context->operand->mem.disp.value), formatter->disp_padding,
    347                 formatter->hex_force_leading_number);
    348             break;
    349         }
    350         ZYAN_FALLTHROUGH;
    351     case ZYDIS_SIGNEDNESS_UNSIGNED:
    352         if ((context->operand->mem.base  != ZYDIS_REGISTER_NONE) ||
    353             (context->operand->mem.index != ZYDIS_REGISTER_NONE))
    354         {
    355             ZYDIS_BUFFER_APPEND(buffer, ADD);
    356         }
    357         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
    358         ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
    359             context->operand->mem.disp.value, formatter->disp_padding,
    360             formatter->hex_force_leading_number);
    361         break;
    362     default:
    363         return ZYAN_STATUS_INVALID_ARGUMENT;
    364     }
    365 
    366     return ZYAN_STATUS_SUCCESS;
    367 }
    368 
    369 ZyanStatus ZydisFormatterIntelPrintTypecast(const ZydisFormatter* formatter,
    370     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    371 {
    372     ZYAN_ASSERT(formatter);
    373     ZYAN_ASSERT(buffer);
    374     ZYAN_ASSERT(context);
    375 
    376     switch (ZydisFormatterHelperGetExplicitSize(formatter, context, context->operand))
    377     {
    378     case   8: ZYDIS_BUFFER_APPEND(buffer, SIZE_8_INTEL  ); break;
    379     case  16: ZYDIS_BUFFER_APPEND(buffer, SIZE_16_INTEL ); break;
    380     case  32: ZYDIS_BUFFER_APPEND(buffer, SIZE_32_INTEL ); break;
    381     case  48: ZYDIS_BUFFER_APPEND(buffer, SIZE_48       ); break;
    382     case  64: ZYDIS_BUFFER_APPEND(buffer, SIZE_64_INTEL ); break;
    383     case  80: ZYDIS_BUFFER_APPEND(buffer, SIZE_80       ); break;
    384     case 128: ZYDIS_BUFFER_APPEND(buffer, SIZE_128_INTEL); break;
    385     case 256: ZYDIS_BUFFER_APPEND(buffer, SIZE_256_INTEL); break;
    386     case 512: ZYDIS_BUFFER_APPEND(buffer, SIZE_512_INTEL); break;
    387     default:
    388         break;
    389     }
    390 
    391     return ZYAN_STATUS_SUCCESS;
    392 }
    393 
    394 /* ---------------------------------------------------------------------------------------------- */
    395 /* MASM                                                                                           */
    396 /* ---------------------------------------------------------------------------------------------- */
    397 
    398 ZyanStatus ZydisFormatterIntelFormatInstructionMASM(const ZydisFormatter* formatter,
    399     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    400 {
    401     ZYAN_ASSERT(formatter);
    402     ZYAN_ASSERT(buffer);
    403     ZYAN_ASSERT(context);
    404 
    405     // Force the formatter to always call our MASM `ZYDIS_FORMATTER_PRINT_ADDRESS_ABS` function.
    406     // This implicitly omits printing of the `RIP`/`EIP` registers for `RIP`/`EIP`-relative
    407     // memory operands
    408     context->runtime_address = 0;
    409 
    410     return ZydisFormatterIntelFormatInstruction(formatter, buffer, context);
    411 }
    412 
    413 ZyanStatus ZydisFormatterIntelPrintAddressMASM(const ZydisFormatter* formatter,
    414     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
    415 {
    416     ZYAN_ASSERT(formatter);
    417     ZYAN_ASSERT(buffer);
    418     ZYAN_ASSERT(context);
    419 
    420     ZyanU64 address;
    421     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
    422 
    423     ZyanU8 padding = (formatter->addr_padding_relative ==
    424         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
    425     if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
    426         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
    427     {
    428         switch (context->instruction->stack_width)
    429         {
    430         case 16:
    431             padding =  4;
    432             address = (ZyanU16)address;
    433             break;
    434         case 32:
    435             padding =  8;
    436             address = (ZyanU32)address;
    437             break;
    438         case 64:
    439             padding = 16;
    440             break;
    441         default:
    442             return ZYAN_STATUS_INVALID_ARGUMENT;
    443         }
    444     }
    445 
    446     ZYDIS_BUFFER_APPEND(buffer, ADDR_RELATIVE);
    447     ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address, padding,
    448         formatter->hex_force_leading_number, ZYAN_TRUE);
    449 
    450     return ZYAN_STATUS_SUCCESS;
    451 }
    452 
    453 /* ---------------------------------------------------------------------------------------------- */
    454 
    455 /* ============================================================================================== */