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

Formatter.c (24842B)


      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 <Zycore/LibC.h>
     28 #include <Zydis/Formatter.h>
     29 #include <Zydis/Internal/FormatterATT.h>
     30 #include <Zydis/Internal/FormatterIntel.h>
     31 #include <Zydis/Internal/String.h>
     32 
     33 /* ============================================================================================== */
     34 /* Constants                                                                                      */
     35 /* ============================================================================================== */
     36 
     37 /* ---------------------------------------------------------------------------------------------- */
     38 /* Formatter presets                                                                              */
     39 /* ---------------------------------------------------------------------------------------------- */
     40 
     41 static const ZydisFormatter* const FORMATTER_PRESETS[ZYDIS_FORMATTER_STYLE_MAX_VALUE + 1] =
     42 {
     43     &FORMATTER_ATT,
     44     &FORMATTER_INTEL,
     45     &FORMATTER_INTEL_MASM
     46 };
     47 
     48 /* ---------------------------------------------------------------------------------------------- */
     49 
     50 /* ============================================================================================== */
     51 /* Internal functions                                                                             */
     52 /* ============================================================================================== */
     53 
     54 /* ---------------------------------------------------------------------------------------------- */
     55 /* Helper functions                                                                               */
     56 /* ---------------------------------------------------------------------------------------------- */
     57 
     58 void ZydisFormatterBufferInit(ZydisFormatterBuffer* buffer, char* user_buffer,
     59     ZyanUSize length)
     60 {
     61     ZYAN_ASSERT(buffer);
     62     ZYAN_ASSERT(user_buffer);
     63     ZYAN_ASSERT(length);
     64 
     65     buffer->is_token_list                   = ZYAN_FALSE;
     66     buffer->capacity                        = 0;
     67     buffer->string.flags                    = ZYAN_STRING_HAS_FIXED_CAPACITY;
     68     buffer->string.vector.allocator         = ZYAN_NULL;
     69     buffer->string.vector.growth_factor     = 1;
     70     buffer->string.vector.shrink_threshold  = 0;
     71     buffer->string.vector.destructor        = ZYAN_NULL;
     72     buffer->string.vector.element_size      = sizeof(char);
     73     buffer->string.vector.size              = 1;
     74     buffer->string.vector.capacity          = length;
     75     buffer->string.vector.data              = user_buffer;
     76 
     77     *user_buffer = '\0';
     78 }
     79 
     80 void ZydisFormatterBufferInitTokenized(ZydisFormatterBuffer* buffer,
     81     ZydisFormatterToken** first_token, void* user_buffer, ZyanUSize length)
     82 {
     83     ZYAN_ASSERT(buffer);
     84     ZYAN_ASSERT(first_token);
     85     ZYAN_ASSERT(user_buffer);
     86     ZYAN_ASSERT(length);
     87 
     88     *first_token = user_buffer;
     89     (*first_token)->type = ZYDIS_TOKEN_INVALID;
     90     (*first_token)->next = 0;
     91 
     92     user_buffer = (ZyanU8*)user_buffer + sizeof(ZydisFormatterToken);
     93     length -= sizeof(ZydisFormatterToken);
     94 
     95     buffer->is_token_list                  = ZYAN_TRUE;
     96     buffer->capacity                       = length;
     97     buffer->string.flags                   = ZYAN_STRING_HAS_FIXED_CAPACITY;
     98     buffer->string.vector.allocator        = ZYAN_NULL;
     99     buffer->string.vector.growth_factor    = 1;
    100     buffer->string.vector.shrink_threshold = 0;
    101     buffer->string.vector.destructor       = ZYAN_NULL;
    102     buffer->string.vector.element_size     = sizeof(char);
    103     buffer->string.vector.size             = 1;
    104     buffer->string.vector.capacity         = length;
    105     buffer->string.vector.data             = user_buffer;
    106 
    107     *(char*)user_buffer = '\0';
    108 }
    109 
    110 /* ---------------------------------------------------------------------------------------------- */
    111 
    112 /* ============================================================================================== */
    113 /* Exported functions                                                                             */
    114 /* ============================================================================================== */
    115 
    116 /* ---------------------------------------------------------------------------------------------- */
    117 /* Initialization                                                                                 */
    118 /* ---------------------------------------------------------------------------------------------- */
    119 
    120 ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style)
    121 {
    122     if (!formatter || ((ZyanUSize)style > ZYDIS_FORMATTER_STYLE_MAX_VALUE))
    123     {
    124         return ZYAN_STATUS_INVALID_ARGUMENT;
    125     }
    126 
    127     ZYAN_MEMCPY(formatter, FORMATTER_PRESETS[style], sizeof(*formatter));
    128 
    129     return ZYAN_STATUS_SUCCESS;
    130 }
    131 
    132 /* ---------------------------------------------------------------------------------------------- */
    133 /* Setter                                                                                         */
    134 /* ---------------------------------------------------------------------------------------------- */
    135 
    136 ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, ZydisFormatterProperty property,
    137     ZyanUPointer value)
    138 {
    139     if (!formatter)
    140     {
    141         return ZYAN_STATUS_INVALID_ARGUMENT;
    142     }
    143 
    144     ZydisNumericBase base = (ZydisNumericBase)(-1);
    145     ZyanU8 index = 0xFF;
    146 
    147     switch (property)
    148     {
    149     case ZYDIS_FORMATTER_PROP_FORCE_SIZE:
    150     {
    151         formatter->force_memory_size = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    152         break;
    153     }
    154     case ZYDIS_FORMATTER_PROP_FORCE_SEGMENT:
    155     {
    156         formatter->force_memory_segment = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    157         break;
    158     }
    159     case ZYDIS_FORMATTER_PROP_FORCE_SCALE_ONE:
    160     {
    161         formatter->force_memory_scale = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    162         break;
    163     }
    164     case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_BRANCHES:
    165     {
    166         formatter->force_relative_branches = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    167         break;
    168     }
    169     case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_RIPREL:
    170     {
    171         formatter->force_relative_riprel = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    172         break;
    173     }
    174     case ZYDIS_FORMATTER_PROP_PRINT_BRANCH_SIZE:
    175     {
    176         formatter->print_branch_size = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    177         break;
    178     }
    179     case ZYDIS_FORMATTER_PROP_DETAILED_PREFIXES:
    180     {
    181         formatter->detailed_prefixes = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    182         break;
    183     }
    184     case ZYDIS_FORMATTER_PROP_ADDR_BASE:
    185     {
    186         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
    187         {
    188             return ZYAN_STATUS_INVALID_ARGUMENT;
    189         }
    190         formatter->addr_base = (ZydisNumericBase)value;
    191         break;
    192     }
    193     case ZYDIS_FORMATTER_PROP_ADDR_SIGNEDNESS:
    194     {
    195         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
    196         {
    197             return ZYAN_STATUS_INVALID_ARGUMENT;
    198         }
    199         formatter->addr_signedness = (ZydisSignedness)value;
    200         break;
    201     }
    202     case ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE:
    203     {
    204         if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) &&
    205             (value > 0xFF))
    206         {
    207             return ZYAN_STATUS_INVALID_ARGUMENT;
    208         }
    209         formatter->addr_padding_absolute = (ZydisPadding)value;
    210         break;
    211     }
    212     case ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE:
    213     {
    214         if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) &&
    215             (value > 0xFF))
    216         {
    217             return ZYAN_STATUS_INVALID_ARGUMENT;
    218         }
    219         formatter->addr_padding_relative = (ZydisPadding)value;
    220         break;
    221     }
    222     case ZYDIS_FORMATTER_PROP_DISP_BASE:
    223     {
    224         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
    225         {
    226             return ZYAN_STATUS_INVALID_ARGUMENT;
    227         }
    228         formatter->disp_base = (ZydisNumericBase)value;
    229         break;
    230     }
    231     case ZYDIS_FORMATTER_PROP_DISP_SIGNEDNESS:
    232     {
    233         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
    234         {
    235             return ZYAN_STATUS_INVALID_ARGUMENT;
    236         }
    237         formatter->disp_signedness = (ZydisSignedness)value;
    238         break;
    239     }
    240     case ZYDIS_FORMATTER_PROP_DISP_PADDING:
    241     {
    242         if ((ZydisPadding)value == ZYDIS_PADDING_AUTO)
    243         {
    244             if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE)
    245             {
    246                 return ZYAN_STATUS_INVALID_ARGUMENT;
    247             }
    248             formatter->disp_padding = FORMATTER_PRESETS[formatter->style]->disp_padding;
    249         }
    250         else if (value > 0xFF)
    251         {
    252             return ZYAN_STATUS_INVALID_ARGUMENT;
    253         }
    254         formatter->disp_padding = (ZydisPadding)value;
    255         break;
    256     }
    257     case ZYDIS_FORMATTER_PROP_IMM_BASE:
    258     {
    259         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
    260         {
    261             return ZYAN_STATUS_INVALID_ARGUMENT;
    262         }
    263         formatter->imm_base = (ZydisNumericBase)value;
    264         break;
    265     }
    266     case ZYDIS_FORMATTER_PROP_IMM_SIGNEDNESS:
    267     {
    268         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
    269         {
    270             return ZYAN_STATUS_INVALID_ARGUMENT;
    271         }
    272         formatter->imm_signedness  = (ZydisSignedness)value;
    273         break;
    274     }
    275     case ZYDIS_FORMATTER_PROP_IMM_PADDING:
    276     {
    277         if ((ZydisPadding)value == ZYDIS_PADDING_AUTO)
    278         {
    279             if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE)
    280             {
    281                 return ZYAN_STATUS_INVALID_ARGUMENT;
    282             }
    283             formatter->imm_padding = FORMATTER_PRESETS[formatter->style]->imm_padding;
    284         }
    285         else if (value > 0xFF)
    286         {
    287             return ZYAN_STATUS_INVALID_ARGUMENT;
    288         }
    289         formatter->imm_padding = (ZydisPadding)value;
    290         break;
    291     }
    292     case ZYDIS_FORMATTER_PROP_UPPERCASE_PREFIXES:
    293     {
    294         formatter->case_prefixes = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
    295         break;
    296     }
    297     case ZYDIS_FORMATTER_PROP_UPPERCASE_MNEMONIC:
    298     {
    299         formatter->case_mnemonic = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
    300         break;
    301     }
    302     case ZYDIS_FORMATTER_PROP_UPPERCASE_REGISTERS:
    303     {
    304         formatter->case_registers = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
    305         break;
    306     }
    307     case ZYDIS_FORMATTER_PROP_UPPERCASE_TYPECASTS:
    308     {
    309         formatter->case_typecasts = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
    310         break;
    311     }
    312     case ZYDIS_FORMATTER_PROP_UPPERCASE_DECORATORS:
    313     {
    314         formatter->case_decorators = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
    315         break;
    316     }
    317     case ZYDIS_FORMATTER_PROP_DEC_PREFIX:
    318     {
    319         base  = ZYDIS_NUMERIC_BASE_DEC;
    320         index = 0;
    321         break;
    322     }
    323     case ZYDIS_FORMATTER_PROP_DEC_SUFFIX:
    324     {
    325         base  = ZYDIS_NUMERIC_BASE_DEC;
    326         index = 1;
    327         break;
    328     }
    329     case ZYDIS_FORMATTER_PROP_HEX_UPPERCASE:
    330     {
    331         formatter->hex_uppercase = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    332         break;
    333     }
    334     case ZYDIS_FORMATTER_PROP_HEX_PREFIX:
    335     {
    336         base  = ZYDIS_NUMERIC_BASE_HEX;
    337         index = 0;
    338         break;
    339     }
    340     case ZYDIS_FORMATTER_PROP_HEX_SUFFIX:
    341     {
    342         base  = ZYDIS_NUMERIC_BASE_HEX;
    343         index = 1;
    344         break;
    345     }
    346     default:
    347         return ZYAN_STATUS_INVALID_ARGUMENT;
    348     }
    349 
    350     // Set prefix or suffix
    351     if (base != (ZydisNumericBase)(-1))
    352     {
    353         if (value)
    354         {
    355             const ZyanUSize len = ZYAN_STRLEN((char*)value);
    356             if (len > 10)
    357             {
    358                 return ZYAN_STATUS_INVALID_ARGUMENT;
    359             }
    360             ZYAN_MEMCPY(formatter->number_format[base][index].buffer, (void*)value, len);
    361             formatter->number_format[base][index].buffer[len] = '\0';
    362             formatter->number_format[base][index].string_data.string.vector.data =
    363                 formatter->number_format[base][index].buffer;
    364             formatter->number_format[base][index].string_data.string.vector.size = len + 1;
    365             formatter->number_format[base][index].string =
    366                 &formatter->number_format[base][index].string_data;
    367         } else
    368         {
    369             formatter->number_format[base][index].string = ZYAN_NULL;
    370         }
    371     }
    372 
    373     return ZYAN_STATUS_SUCCESS;
    374 }
    375 
    376 ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, ZydisFormatterFunction type,
    377     const void** callback)
    378 {
    379     if (!formatter || !callback || ((ZyanUSize)type > ZYDIS_FORMATTER_FUNC_MAX_VALUE))
    380     {
    381         return ZYAN_STATUS_INVALID_ARGUMENT;
    382     }
    383 
    384     const void* const temp = *callback;
    385 
    386     // The following code relies on the order of the enum values and the function fields inside
    387     // the `ZydisFormatter` struct
    388 
    389 #ifdef ZYAN_DEBUG
    390     const ZyanUPointer* test = (ZyanUPointer*)(&formatter->func_pre_instruction + type);
    391     switch (type)
    392     {
    393     case ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION:
    394         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_instruction   ); break;
    395     case ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION:
    396         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_instruction  ); break;
    397     case ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION:
    398         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_instruction); break;
    399     case ZYDIS_FORMATTER_FUNC_PRE_OPERAND:
    400         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_operand       ); break;
    401     case ZYDIS_FORMATTER_FUNC_POST_OPERAND:
    402         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_operand      ); break;
    403     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG:
    404         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_reg); break;
    405     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM:
    406         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_mem); break;
    407     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR:
    408         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_ptr); break;
    409     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM:
    410         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_imm); break;
    411     case ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC:
    412         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_mnemonic    ); break;
    413     case ZYDIS_FORMATTER_FUNC_PRINT_REGISTER:
    414         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_register    ); break;
    415     case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS:
    416         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_abs ); break;
    417     case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL:
    418         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_rel ); break;
    419     case ZYDIS_FORMATTER_FUNC_PRINT_DISP:
    420         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_disp        ); break;
    421     case ZYDIS_FORMATTER_FUNC_PRINT_IMM:
    422         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_imm         ); break;
    423     case ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST:
    424         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_typecast    ); break;
    425     case ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT:
    426         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_segment     ); break;
    427     case ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES:
    428         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_prefixes    ); break;
    429     case ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR:
    430         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_decorator   ); break;
    431     default:
    432         ZYAN_UNREACHABLE;
    433     }
    434 #endif
    435 
    436     *callback = *(const void**)(&formatter->func_pre_instruction + type);
    437     if (!temp)
    438     {
    439         return ZYAN_STATUS_SUCCESS;
    440     }
    441     ZYAN_MEMCPY(&formatter->func_pre_instruction + type, &temp, sizeof(ZyanUPointer));
    442 
    443     return ZYAN_STATUS_SUCCESS;
    444 }
    445 
    446 /* ---------------------------------------------------------------------------------------------- */
    447 /* Formatting                                                                                     */
    448 /* ---------------------------------------------------------------------------------------------- */
    449 
    450 ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter,
    451     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
    452     ZyanU8 operand_count, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
    453 {
    454     if (!formatter || !instruction || (operand_count && !operands) ||
    455         (operand_count > ZYDIS_MAX_OPERAND_COUNT) ||
    456         (operand_count < instruction->operand_count_visible) || !buffer || (length == 0))
    457     {
    458         return ZYAN_STATUS_INVALID_ARGUMENT;
    459     }
    460 
    461     ZydisFormatterBuffer formatter_buffer;
    462     ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
    463 
    464     ZydisFormatterContext context;
    465     context.instruction     = instruction;
    466     context.operands        = operands;
    467     context.runtime_address = runtime_address;
    468     context.operand         = ZYAN_NULL;
    469     context.user_data       = user_data;
    470 
    471     if (formatter->func_pre_instruction)
    472     {
    473         ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
    474     }
    475 
    476     ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
    477 
    478     if (formatter->func_post_instruction)
    479     {
    480         ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
    481     }
    482 
    483     return ZYAN_STATUS_SUCCESS;
    484 }
    485 
    486 ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter,
    487     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
    488     char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
    489 {
    490     if (!formatter || !instruction || !operand || !buffer || (length == 0))
    491     {
    492         return ZYAN_STATUS_INVALID_ARGUMENT;
    493     }
    494 
    495     ZydisFormatterBuffer formatter_buffer;
    496     ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
    497 
    498     ZydisFormatterContext context;
    499     context.instruction     = instruction;
    500     context.operands        = ZYAN_NULL;
    501     context.runtime_address = runtime_address;
    502     context.operand         = operand;
    503     context.user_data       = user_data;
    504 
    505     // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
    506     // to skip the only operand printed by this function
    507 
    508     if (formatter->func_pre_operand)
    509     {
    510         ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
    511     }
    512 
    513     switch (context.operand->type)
    514     {
    515     case ZYDIS_OPERAND_TYPE_REGISTER:
    516         ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
    517         break;
    518     case ZYDIS_OPERAND_TYPE_MEMORY:
    519         ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
    520         break;
    521     case ZYDIS_OPERAND_TYPE_IMMEDIATE:
    522         ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
    523         break;
    524     case ZYDIS_OPERAND_TYPE_POINTER:
    525         ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
    526         break;
    527     default:
    528         return ZYAN_STATUS_INVALID_ARGUMENT;
    529     }
    530 
    531     if (formatter->func_post_operand)
    532     {
    533         ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
    534     }
    535 
    536     return ZYAN_STATUS_SUCCESS;
    537 }
    538 
    539 /* ---------------------------------------------------------------------------------------------- */
    540 /* Tokenizing                                                                                     */
    541 /* ---------------------------------------------------------------------------------------------- */
    542 
    543 ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter,
    544     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
    545     ZyanU8 operand_count, void* buffer, ZyanUSize length, ZyanU64 runtime_address,
    546     ZydisFormatterTokenConst** token, void* user_data)
    547 {
    548     if (!formatter || !instruction || (operand_count && !operands) ||
    549         (operand_count > ZYDIS_MAX_OPERAND_COUNT) || 
    550         (operand_count < instruction->operand_count_visible) || !buffer ||
    551         (length <= sizeof(ZydisFormatterToken)) || !token)
    552     {
    553         return ZYAN_STATUS_INVALID_ARGUMENT;
    554     }
    555 
    556     ZydisFormatterBuffer formatter_buffer;
    557     ZydisFormatterToken* first_token;
    558     ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
    559 
    560     ZydisFormatterContext context;
    561     context.instruction     = instruction;
    562     context.operands        = operands;
    563     context.runtime_address = runtime_address;
    564     context.operand         = ZYAN_NULL;
    565     context.user_data       = user_data;
    566 
    567     if (formatter->func_pre_instruction)
    568     {
    569         ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
    570     }
    571 
    572     ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
    573 
    574     if (formatter->func_post_instruction)
    575     {
    576         ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
    577     }
    578 
    579     if (first_token->next)
    580     {
    581         *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
    582             first_token->next);
    583         return ZYAN_STATUS_SUCCESS;
    584     }
    585 
    586     *token = first_token;
    587     return ZYAN_STATUS_SUCCESS;
    588 }
    589 
    590 ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter,
    591     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
    592     void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token,
    593     void* user_data)
    594 {
    595     if (!formatter || !instruction || !operand || !buffer ||
    596         (length <= sizeof(ZydisFormatterToken)) || !token)
    597     {
    598         return ZYAN_STATUS_INVALID_ARGUMENT;
    599     }
    600 
    601     ZydisFormatterToken* first_token;
    602     ZydisFormatterBuffer formatter_buffer;
    603     ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
    604 
    605     ZydisFormatterContext context;
    606     context.instruction     = instruction;
    607     context.operands        = ZYAN_NULL;
    608     context.runtime_address = runtime_address;
    609     context.operand         = operand;
    610     context.user_data       = user_data;
    611 
    612     // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
    613     // to skip the only operand printed by this function
    614 
    615     if (formatter->func_pre_operand)
    616     {
    617         ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
    618     }
    619 
    620     switch (context.operand->type)
    621     {
    622     case ZYDIS_OPERAND_TYPE_REGISTER:
    623         ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
    624         break;
    625     case ZYDIS_OPERAND_TYPE_MEMORY:
    626         ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
    627         break;
    628     case ZYDIS_OPERAND_TYPE_IMMEDIATE:
    629         ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
    630         break;
    631     case ZYDIS_OPERAND_TYPE_POINTER:
    632         ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
    633         break;
    634     default:
    635         return ZYAN_STATUS_INVALID_ARGUMENT;
    636     }
    637 
    638     if (formatter->func_post_operand)
    639     {
    640         ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
    641     }
    642 
    643     if (first_token->next)
    644     {
    645         *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
    646             first_token->next);
    647         return ZYAN_STATUS_SUCCESS;
    648     }
    649 
    650     *token = first_token;
    651     return ZYAN_STATUS_SUCCESS;
    652 }
    653 
    654 /* ============================================================================================== */
    655 
    656 /* ============================================================================================== */