Coverage Report

Created: 2025-07-18 06:33

/src/zydis/include/Zydis/Internal/FormatterBase.h
Line
Count
Source (jump to first uncovered line)
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
0
    switch (base) \
64
0
    { \
65
0
    case ZYDIS_NUMERIC_BASE_DEC: \
66
0
        ZYAN_CHECK(ZydisStringAppendDecU(str, value, padding_length, \
67
0
            (formatter)->number_format[base][0].string, \
68
0
            (formatter)->number_format[base][1].string)); \
69
0
        break; \
70
0
    case ZYDIS_NUMERIC_BASE_HEX: \
71
0
        ZYAN_CHECK(ZydisStringAppendHexU(str, value, padding_length, force_leading_number, \
72
0
            (formatter)->hex_uppercase, \
73
0
            (formatter)->number_format[base][0].string, \
74
0
            (formatter)->number_format[base][1].string)); \
75
0
        break; \
76
0
    default: \
77
0
        return ZYAN_STATUS_INVALID_ARGUMENT; \
78
0
    }
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
0
    switch (base) \
95
0
    { \
96
0
    case ZYDIS_NUMERIC_BASE_DEC: \
97
0
        ZYAN_CHECK(ZydisStringAppendDecS(str, value, padding_length, force_sign, \
98
0
            (formatter)->number_format[base][0].string, \
99
0
            (formatter)->number_format[base][1].string)); \
100
0
        break; \
101
0
    case ZYDIS_NUMERIC_BASE_HEX: \
102
0
        ZYAN_CHECK(ZydisStringAppendHexS(str, value, padding_length, force_leading_number,  \
103
0
            (formatter)->hex_uppercase, force_sign, \
104
0
            (formatter)->number_format[base][0].string, \
105
0
            (formatter)->number_format[base][1].string)); \
106
0
        break; \
107
0
    default: \
108
0
        return ZYAN_STATUS_INVALID_ARGUMENT; \
109
0
    }
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
0
    if ((buffer)->is_token_list) \
127
0
    { \
128
0
        ZYAN_CHECK(ZydisFormatterBufferAppend(buffer, type)); \
129
0
    }
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
0
    if ((buffer)->is_token_list) \
142
0
    { \
143
0
        (state) = (ZyanUPointer)(buffer)->string.vector.data; \
144
0
    } else \
145
0
    { \
146
0
        (state) = (ZyanUPointer)(buffer)->string.vector.size; \
147
0
    }
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
0
    if ((buffer)->is_token_list) \
157
0
    { \
158
0
        ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
159
0
    } else \
160
0
    { \
161
0
        ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ ## name)); \
162
0
    }
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
0
    if ((buffer)->is_token_list) \
175
0
    { \
176
0
        ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer, TOK_ ## name)); \
177
0
    } else \
178
0
    { \
179
0
        ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, &STR_ ## name, letter_case)); \
180
0
    }
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
0
{
227
0
    ZYAN_ASSERT(buffer);
228
0
    ZYAN_ASSERT(data);
229
230
    // TODO: Merge with last token, if `last->type == predefined->first_token.type`
231
232
0
    const ZyanUSize len = buffer->string.vector.size;
233
0
    ZYAN_ASSERT((len > 0) && (len < 256));
234
0
    if (buffer->capacity <= len + data->size)
235
0
    {
236
0
        return ZYAN_STATUS_INSUFFICIENT_BUFFER_SIZE;
237
0
    }
238
239
0
    ZydisFormatterToken* const last = (ZydisFormatterToken*)buffer->string.vector.data - 1;
240
0
    last->next = (ZyanU8)len;
241
242
0
    ZYAN_MEMCPY((ZyanU8*)buffer->string.vector.data + len, &data->data[0], data->size);
243
244
0
    const ZyanUSize delta = len + data->next;
245
0
    buffer->capacity -= delta;
246
0
    buffer->string.vector.data = (ZyanU8*)buffer->string.vector.data + delta;
247
0
    buffer->string.vector.size = data->size - data->next;
248
0
    buffer->string.vector.capacity = ZYAN_MIN(buffer->capacity, 255);
249
250
0
    return ZYAN_STATUS_SUCCESS;
251
0
}
Unexecuted instantiation: Formatter.c:ZydisFormatterBufferAppendPredefined
Unexecuted instantiation: FormatterATT.c:ZydisFormatterBufferAppendPredefined
Unexecuted instantiation: FormatterBase.c:ZydisFormatterBufferAppendPredefined
Unexecuted instantiation: FormatterIntel.c:ZydisFormatterBufferAppendPredefined
252
253
/* ---------------------------------------------------------------------------------------------- */
254
/* General                                                                                        */
255
/* ---------------------------------------------------------------------------------------------- */
256
257
/**
258
 * Returns the size to be used as explicit size suffix (`AT&T`) or explicit typecast
259
 * (`INTEL`), if required.
260
 *
261
 * @param   formatter   A pointer to the `ZydisFormatter` instance.
262
 * @param   context     A pointer to the `ZydisFormatterContext` struct.
263
 * @param   operand     The instructions first memory operand.
264
 *
265
 * @return  Returns the explicit size, if required, or `0`, if not needed.
266
 *
267
 * This function always returns a size different to `0`, if the `ZYDIS_FORMATTER_PROP_FORCE_SIZE`
268
 * is set to `ZYAN_TRUE`.
269
 */
270
ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
271
    ZydisFormatterContext* context, const ZydisDecodedOperand* operand);
272
273
/* ---------------------------------------------------------------------------------------------- */
274
275
/* ============================================================================================== */
276
/* Formatter functions                                                                            */
277
/* ============================================================================================== */
278
279
/* ---------------------------------------------------------------------------------------------- */
280
/* Operands                                                                                       */
281
/* ---------------------------------------------------------------------------------------------- */
282
283
ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
284
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
285
286
ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
287
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
288
289
ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
290
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
291
292
/* ---------------------------------------------------------------------------------------------- */
293
/* Elemental tokens                                                                               */
294
/* ---------------------------------------------------------------------------------------------- */
295
296
ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
297
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
298
299
ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
300
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
301
302
ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
303
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
304
305
/* ---------------------------------------------------------------------------------------------- */
306
/* Optional tokens                                                                                */
307
/* ---------------------------------------------------------------------------------------------- */
308
309
ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
310
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
311
312
ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
313
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context);
314
315
ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
316
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator);
317
318
/* ---------------------------------------------------------------------------------------------- */
319
320
/* ============================================================================================== */
321
322
#ifdef __cplusplus
323
}
324
#endif
325
326
#endif // ZYDIS_FORMATTER_BASE_H