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.h (13722B)


      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 /**
     28  * @file
     29  * Provides formatter functions that are shared between the different formatters.
     30  */
     31 
     32 #ifndef ZYDIS_FORMATTER_BASE_H
     33 #define ZYDIS_FORMATTER_BASE_H
     34 
     35 #include <Zydis/Formatter.h>
     36 #include <Zydis/Internal/String.h>
     37 
     38 #ifdef __cplusplus
     39 extern "C" {
     40 #endif
     41 
     42 /* ============================================================================================== */
     43 /* Macros                                                                                         */
     44 /* ============================================================================================== */
     45 
     46 /* ---------------------------------------------------------------------------------------------- */
     47 /* String                                                                                         */
     48 /* ---------------------------------------------------------------------------------------------- */
     49 
     50 /**
     51  * Appends an unsigned numeric value to the given string.
     52  *
     53  * @param   formatter               A pointer to the `ZydisFormatter` instance.
     54  * @param   base                    The numeric base.
     55  * @param   str                     The destination string.
     56  * @param   value                   The value to append.
     57  * @param   padding_length          The padding length.
     58  * @param   force_leading_number    Enable this option to prepend a leading `0` if the first
     59  *                                  character is non-numeric.
     60  */
     61 #define ZYDIS_STRING_APPEND_NUM_U(formatter, base, str, value, padding_length, \
     62     force_leading_number) \
     63     switch (base) \
     64     { \
     65     case ZYDIS_NUMERIC_BASE_DEC: \
     66         ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \
     67             (formatter)->number_format[base][0].string, \
     68             (formatter)->number_format[base][1].string)); \
     69         break; \
     70     case ZYDIS_NUMERIC_BASE_HEX: \
     71         ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, force_leading_number, \
     72             (formatter)->hex_uppercase, \
     73             (formatter)->number_format[base][0].string, \
     74             (formatter)->number_format[base][1].string)); \
     75         break; \
     76     default: \
     77         return ZYAN_STATUS_INVALID_ARGUMENT; \
     78     }
     79 
     80 /**
     81  * Appends a signed numeric value to the given string.
     82  *
     83  * @param   formatter               A pointer to the `ZydisFormatter` instance.
     84  * @param   base                    The numeric base.
     85  * @param   str                     The destination string.
     86  * @param   value                   The value to append.
     87  * @param   padding_length          The padding length.
     88  * @param   force_leading_number    Enable this option to prepend a leading `0`, if the first
     89  *                                  character is non-numeric.
     90  * @param   force_sign              Enable to print the '+' sign for positive numbers.
     91  */
     92 #define ZYDIS_STRING_APPEND_NUM_S(formatter, base, str, value, padding_length, \
     93     force_leading_number, force_sign) \
     94     switch (base) \
     95     { \
     96     case ZYDIS_NUMERIC_BASE_DEC: \
     97         ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \
     98             (formatter)->number_format[base][0].string, \
     99             (formatter)->number_format[base][1].string)); \
    100         break; \
    101     case ZYDIS_NUMERIC_BASE_HEX: \
    102         ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, force_leading_number,  \
    103             (formatter)->hex_uppercase, force_sign, \
    104             (formatter)->number_format[base][0].string, \
    105             (formatter)->number_format[base][1].string)); \
    106         break; \
    107     default: \
    108         return ZYAN_STATUS_INVALID_ARGUMENT; \
    109     }
    110 
    111 /* ---------------------------------------------------------------------------------------------- */
    112 /* Buffer                                                                                         */
    113 /* ---------------------------------------------------------------------------------------------- */
    114 
    115 /**
    116  * Invokes the `ZydisFormatterBufferAppend` routine, if tokenization is enabled for the
    117  * current pass.
    118  *
    119  * @param   buffer  A pointer to the `ZydisFormatterBuffer` struct.
    120  * @param   type    The token type.
    121  *
    122  * Using this macro instead of direct calls to `ZydisFormatterBufferAppend` greatly improves the
    123  * performance for non-tokenizing passes.
    124  */
    125 #define ZYDIS_BUFFER_APPEND_TOKEN(buffer, type) \
    126     if ((buffer)->is_token_list) \
    127     { \
    128         ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \
    129     }
    130 
    131 /**
    132  * Returns a snapshot of the buffer-state.
    133  *
    134  * @param   buffer  A pointer to the `ZydisFormatterBuffer` struct.
    135  * @param   state   Receives a snapshot of the buffer-state.
    136  *
    137  * Using this macro instead of direct calls to `ZydisFormatterBufferRemember` improves the
    138  * performance for non-tokenizing passes.
    139  */
    140 #define ZYDIS_BUFFER_REMEMBER(buffer, state) \
    141     if ((buffer)->is_token_list) \
    142     { \
    143         (state) = (ZyanUPointer)(buffer)->string.vector.data; \
    144     } else \
    145     { \
    146         (state) = (ZyanUPointer)(buffer)->string.vector.size; \
    147     }
    148 
    149 /**
    150  * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
    151  *
    152  * @param   buffer  A pointer to the `ZydisFormatterBuffer` struct.
    153  * @param   name    The base name (without prefix) of the string- or token.
    154  */
    155 #define ZYDIS_BUFFER_APPEND(buffer, name) \
    156     if ((buffer)->is_token_list) \
    157     { \
    158         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
    159     } else \
    160     { \
    161         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \
    162     }
    163 
    164 // TODO: Implement `letter_case` for predefined tokens
    165 
    166 /**
    167  * Appends a string (`STR_`-prefix) or a predefined token-list (`TOK_`-prefix).
    168  *
    169  * @param   buffer      A pointer to the `ZydisFormatterBuffer` struct.
    170  * @param   name        The base name (without prefix) of the string- or token.
    171  * @param   letter_case The desired letter-case.
    172  */
    173 #define ZYDIS_BUFFER_APPEND_CASE(buffer, name, letter_case) \
    174     if ((buffer)->is_token_list) \
    175     { \
    176         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
    177     } else \
    178     { \
    179         ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \
    180     }
    181 
    182 /* ---------------------------------------------------------------------------------------------- */
    183 
    184 /* ============================================================================================== */
    185 /* Helper functions                                                                               */
    186 /* ============================================================================================== */
    187 
    188 /* ---------------------------------------------------------------------------------------------- */
    189 /* Buffer                                                                                         */
    190 /* ---------------------------------------------------------------------------------------------- */
    191 
    192 // MSVC does not like the C99 flexible-array extension
    193 #ifdef ZYAN_MSVC
    194 #   pragma warning(push)
    195 #   pragma warning(disable:4200)
    196 #endif
    197 
    198 #pragma pack(push, 1)
    199 
    200 typedef struct ZydisPredefinedToken_
    201 {
    202     ZyanU8 size;
    203     ZyanU8 next;
    204     ZyanU8 data[];
    205 } ZydisPredefinedToken;
    206 
    207 #pragma pack(pop)
    208 
    209 #ifdef ZYAN_MSVC
    210 #   pragma warning(pop)
    211 #endif
    212 
    213 /**
    214  * Appends a predefined token-list to the `buffer`.
    215  *
    216  * @param   buffer  A pointer to the `ZydisFormatterBuffer` struct.
    217  * @param   data    A pointer to the `ZydisPredefinedToken` struct.
    218  *
    219  * @return  A zycore status code.
    220  *
    221  * This function is internally used to improve performance while adding static strings or multiple
    222  * tokens at once.
    223  */
    224 ZYAN_INLINE ZyanStatus ZydisFormatterBufferAppendPredefined(ZydisFormatterBuffer* buffer,
    225     const ZydisPredefinedToken* data)
    226 {
    227     ZYAN_ASSERT(buffer);
    228     ZYAN_ASSERT(data);
    229 
    230     const ZyanUSize len = buffer->string.vector.size;
    231     ZYAN_ASSERT((len > 0) && (len < 256));
    232     if (buffer->capacity <= len + data->size)
    233     {
    234         return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
    235     }
    236 
    237     ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1;
    238     last->next = (ZyanU8)len;
    239 
    240     ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size);
    241 
    242     const ZyanUSize delta = len + data->next;
    243     buffer->capacity -= delta;
    244     buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta;
    245     buffer->string.vector.size = data->size - data->next;
    246     buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255);
    247 
    248     return ZYAN_STATUS_SUCCESS;
    249 }
    250 
    251 /* ---------------------------------------------------------------------------------------------- */
    252 /* General                                                                                        */
    253 /* ---------------------------------------------------------------------------------------------- */
    254 
    255 /**
    256  * Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast
    257  * (`INTEL`), if required.
    258  *
    259  * @param   formatter   A pointer to the `ZydisFormatter` instance.
    260  * @param   context     A pointer to the `ZydisFormatterContext` struct.
    261  * @param   operand     The instructions first memory operand.
    262  *
    263  * @return  Returns the explicit size, if required, or `0`, if not needed.
    264  *
    265  * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE`
    266  * is set to `ZYAN_TRUE`.
    267  */
    268 ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
    269     ZydisFormatterContext* context, const ZydisDecodedOperand* operand);
    270 
    271 /* ---------------------------------------------------------------------------------------------- */
    272 
    273 /* ============================================================================================== */
    274 /* Formatter functions                                                                            */
    275 /* ============================================================================================== */
    276 
    277 /* ---------------------------------------------------------------------------------------------- */
    278 /* Operands                                                                                       */
    279 /* ---------------------------------------------------------------------------------------------- */
    280 
    281 ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
    282     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    283 
    284 ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
    285     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    286 
    287 ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
    288     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    289 
    290 /* ---------------------------------------------------------------------------------------------- */
    291 /* Elemental tokens                                                                               */
    292 /* ---------------------------------------------------------------------------------------------- */
    293 
    294 ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
    295     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    296 
    297 ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
    298     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    299 
    300 ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
    301     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    302 
    303 /* ---------------------------------------------------------------------------------------------- */
    304 /* Optional tokens                                                                                */
    305 /* ---------------------------------------------------------------------------------------------- */
    306 
    307 ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
    308     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    309 
    310 ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
    311     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
    312 
    313 ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
    314     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator);
    315 
    316 /* ---------------------------------------------------------------------------------------------- */
    317 
    318 /* ============================================================================================== */
    319 
    320 #ifdef __cplusplus
    321 }
    322 #endif
    323 
    324 #endif // ZYDIS_FORMATTER_BASE_H