tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Formatter.c (25049B)


      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/Zycore/LibC.h"
     28 #include "zydis/Zydis/Formatter.h"
     29 #include "zydis/Zydis/Internal/FormatterATT.h"
     30 #include "zydis/Zydis/Internal/FormatterIntel.h"
     31 #include "zydis/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 static 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 static 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_FORCE_LEADING_NUMBER:
    335    {
    336        formatter->hex_force_leading_number = (value) ? ZYAN_TRUE : ZYAN_FALSE;
    337        break;
    338    }
    339    case ZYDIS_FORMATTER_PROP_HEX_PREFIX:
    340    {
    341        base  = ZYDIS_NUMERIC_BASE_HEX;
    342        index = 0;
    343        break;
    344    }
    345    case ZYDIS_FORMATTER_PROP_HEX_SUFFIX:
    346    {
    347        base  = ZYDIS_NUMERIC_BASE_HEX;
    348        index = 1;
    349        break;
    350    }
    351    default:
    352        return ZYAN_STATUS_INVALID_ARGUMENT;
    353    }
    354 
    355    // Set prefix or suffix
    356    if (base != (ZydisNumericBase)(-1))
    357    {
    358        if (value)
    359        {
    360            const ZyanUSize len = ZYAN_STRLEN((char*)value);
    361            if (len > 10)
    362            {
    363                return ZYAN_STATUS_INVALID_ARGUMENT;
    364            }
    365            ZYAN_MEMCPY(formatter->number_format[base][index].buffer, (void*)value, len);
    366            formatter->number_format[base][index].buffer[len] = '\0';
    367            formatter->number_format[base][index].string_data.string.vector.data =
    368                formatter->number_format[base][index].buffer;
    369            formatter->number_format[base][index].string_data.string.vector.size = len + 1;
    370            formatter->number_format[base][index].string =
    371                &formatter->number_format[base][index].string_data;
    372        } else
    373        {
    374            formatter->number_format[base][index].string = ZYAN_NULL;
    375        }
    376    }
    377 
    378    return ZYAN_STATUS_SUCCESS;
    379 }
    380 
    381 ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, ZydisFormatterFunction type,
    382    const void** callback)
    383 {
    384    if (!formatter || !callback || ((ZyanUSize)type > ZYDIS_FORMATTER_FUNC_MAX_VALUE))
    385    {
    386        return ZYAN_STATUS_INVALID_ARGUMENT;
    387    }
    388 
    389    const void* const temp = *callback;
    390 
    391    // The following code relies on the order of the enum values and the function fields inside
    392    // the `ZydisFormatter` struct
    393 
    394 #ifdef ZYAN_DEBUG
    395    const ZyanUPointer* test = (ZyanUPointer*)(&formatter->func_pre_instruction + type);
    396    switch (type)
    397    {
    398    case ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION:
    399        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_instruction   ); break;
    400    case ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION:
    401        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_instruction  ); break;
    402    case ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION:
    403        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_instruction); break;
    404    case ZYDIS_FORMATTER_FUNC_PRE_OPERAND:
    405        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_operand       ); break;
    406    case ZYDIS_FORMATTER_FUNC_POST_OPERAND:
    407        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_operand      ); break;
    408    case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG:
    409        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_reg); break;
    410    case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM:
    411        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_mem); break;
    412    case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR:
    413        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_ptr); break;
    414    case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM:
    415        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_imm); break;
    416    case ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC:
    417        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_mnemonic    ); break;
    418    case ZYDIS_FORMATTER_FUNC_PRINT_REGISTER:
    419        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_register    ); break;
    420    case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS:
    421        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_abs ); break;
    422    case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL:
    423        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_rel ); break;
    424    case ZYDIS_FORMATTER_FUNC_PRINT_DISP:
    425        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_disp        ); break;
    426    case ZYDIS_FORMATTER_FUNC_PRINT_IMM:
    427        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_imm         ); break;
    428    case ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST:
    429        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_typecast    ); break;
    430    case ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT:
    431        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_segment     ); break;
    432    case ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES:
    433        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_prefixes    ); break;
    434    case ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR:
    435        ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_decorator   ); break;
    436    default:
    437        ZYAN_UNREACHABLE;
    438    }
    439 #endif
    440 
    441    *callback = *(const void**)(&formatter->func_pre_instruction + type);
    442    if (!temp)
    443    {
    444        return ZYAN_STATUS_SUCCESS;
    445    }
    446    ZYAN_MEMCPY(&formatter->func_pre_instruction + type, &temp, sizeof(ZyanUPointer));
    447 
    448    return ZYAN_STATUS_SUCCESS;
    449 }
    450 
    451 /* ---------------------------------------------------------------------------------------------- */
    452 /* Formatting                                                                                     */
    453 /* ---------------------------------------------------------------------------------------------- */
    454 
    455 ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter,
    456    const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
    457    ZyanU8 operand_count, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
    458 {
    459    if (!formatter || !instruction || (operand_count && !operands) ||
    460        (operand_count > ZYDIS_MAX_OPERAND_COUNT) ||
    461        (operand_count < instruction->operand_count_visible) || !buffer || (length == 0))
    462    {
    463        return ZYAN_STATUS_INVALID_ARGUMENT;
    464    }
    465 
    466    ZydisFormatterBuffer formatter_buffer;
    467    ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
    468 
    469    ZydisFormatterContext context;
    470    context.instruction     = instruction;
    471    context.operands        = operands;
    472    context.runtime_address = runtime_address;
    473    context.operand         = ZYAN_NULL;
    474    context.user_data       = user_data;
    475 
    476    if (formatter->func_pre_instruction)
    477    {
    478        ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
    479    }
    480 
    481    ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
    482 
    483    if (formatter->func_post_instruction)
    484    {
    485        ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
    486    }
    487 
    488    return ZYAN_STATUS_SUCCESS;
    489 }
    490 
    491 ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter,
    492    const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
    493    char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
    494 {
    495    if (!formatter || !instruction || !operand || !buffer || (length == 0))
    496    {
    497        return ZYAN_STATUS_INVALID_ARGUMENT;
    498    }
    499 
    500    ZydisFormatterBuffer formatter_buffer;
    501    ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
    502 
    503    ZydisFormatterContext context;
    504    context.instruction     = instruction;
    505    context.operands        = ZYAN_NULL;
    506    context.runtime_address = runtime_address;
    507    context.operand         = operand;
    508    context.user_data       = user_data;
    509 
    510    // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
    511    // to skip the only operand printed by this function
    512 
    513    if (formatter->func_pre_operand)
    514    {
    515        ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
    516    }
    517 
    518    switch (context.operand->type)
    519    {
    520    case ZYDIS_OPERAND_TYPE_REGISTER:
    521        ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
    522        break;
    523    case ZYDIS_OPERAND_TYPE_MEMORY:
    524        ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
    525        break;
    526    case ZYDIS_OPERAND_TYPE_IMMEDIATE:
    527        ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
    528        break;
    529    case ZYDIS_OPERAND_TYPE_POINTER:
    530        ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
    531        break;
    532    default:
    533        return ZYAN_STATUS_INVALID_ARGUMENT;
    534    }
    535 
    536    if (formatter->func_post_operand)
    537    {
    538        ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
    539    }
    540 
    541    return ZYAN_STATUS_SUCCESS;
    542 }
    543 
    544 /* ---------------------------------------------------------------------------------------------- */
    545 /* Tokenizing                                                                                     */
    546 /* ---------------------------------------------------------------------------------------------- */
    547 
    548 ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter,
    549    const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
    550    ZyanU8 operand_count, void* buffer, ZyanUSize length, ZyanU64 runtime_address,
    551    ZydisFormatterTokenConst** token, void* user_data)
    552 {
    553    if (!formatter || !instruction || (operand_count && !operands) ||
    554        (operand_count > ZYDIS_MAX_OPERAND_COUNT) || 
    555        (operand_count < instruction->operand_count_visible) || !buffer ||
    556        (length <= sizeof(ZydisFormatterToken)) || !token)
    557    {
    558        return ZYAN_STATUS_INVALID_ARGUMENT;
    559    }
    560 
    561    ZydisFormatterBuffer formatter_buffer;
    562    ZydisFormatterToken* first_token;
    563    ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
    564 
    565    ZydisFormatterContext context;
    566    context.instruction     = instruction;
    567    context.operands        = operands;
    568    context.runtime_address = runtime_address;
    569    context.operand         = ZYAN_NULL;
    570    context.user_data       = user_data;
    571 
    572    if (formatter->func_pre_instruction)
    573    {
    574        ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
    575    }
    576 
    577    ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
    578 
    579    if (formatter->func_post_instruction)
    580    {
    581        ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
    582    }
    583 
    584    if (first_token->next)
    585    {
    586        *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
    587            first_token->next);
    588        return ZYAN_STATUS_SUCCESS;
    589    }
    590 
    591    *token = first_token;
    592    return ZYAN_STATUS_SUCCESS;
    593 }
    594 
    595 ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter,
    596    const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
    597    void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token,
    598    void* user_data)
    599 {
    600    if (!formatter || !instruction || !operand || !buffer ||
    601        (length <= sizeof(ZydisFormatterToken)) || !token)
    602    {
    603        return ZYAN_STATUS_INVALID_ARGUMENT;
    604    }
    605 
    606    ZydisFormatterToken* first_token;
    607    ZydisFormatterBuffer formatter_buffer;
    608    ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
    609 
    610    ZydisFormatterContext context;
    611    context.instruction     = instruction;
    612    context.operands        = ZYAN_NULL;
    613    context.runtime_address = runtime_address;
    614    context.operand         = operand;
    615    context.user_data       = user_data;
    616 
    617    // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
    618    // to skip the only operand printed by this function
    619 
    620    if (formatter->func_pre_operand)
    621    {
    622        ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
    623    }
    624 
    625    switch (context.operand->type)
    626    {
    627    case ZYDIS_OPERAND_TYPE_REGISTER:
    628        ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
    629        break;
    630    case ZYDIS_OPERAND_TYPE_MEMORY:
    631        ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
    632        break;
    633    case ZYDIS_OPERAND_TYPE_IMMEDIATE:
    634        ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
    635        break;
    636    case ZYDIS_OPERAND_TYPE_POINTER:
    637        ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
    638        break;
    639    default:
    640        return ZYAN_STATUS_INVALID_ARGUMENT;
    641    }
    642 
    643    if (formatter->func_post_operand)
    644    {
    645        ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
    646    }
    647 
    648    if (first_token->next)
    649    {
    650        *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
    651            first_token->next);
    652        return ZYAN_STATUS_SUCCESS;
    653    }
    654 
    655    *token = first_token;
    656    return ZYAN_STATUS_SUCCESS;
    657 }
    658 
    659 /* ============================================================================================== */
    660 
    661 /* ============================================================================================== */