Coverage Report

Created: 2026-05-02 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zydis/src/FormatterBase.c
Line
Count
Source
1
/***************************************************************************************************
2
3
  Zyan Disassembler Library (Zydis)
4
5
  Original Author : Florian Bernd, Joel Hoener
6
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in all
15
 * copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
 * SOFTWARE.
24
25
***************************************************************************************************/
26
27
#include <Zydis/Internal/FormatterBase.h>
28
#include <Zydis/Utils.h>
29
30
/* ============================================================================================== */
31
/* Constants                                                                                      */
32
/* ============================================================================================== */
33
34
#include <Generated/FormatterStrings.inc>
35
36
static const ZydisShortString* const STR_PREF_REX[16] =
37
{
38
    &STR_PREF_REX_40,
39
    &STR_PREF_REX_41,
40
    &STR_PREF_REX_42,
41
    &STR_PREF_REX_43,
42
    &STR_PREF_REX_44,
43
    &STR_PREF_REX_45,
44
    &STR_PREF_REX_46,
45
    &STR_PREF_REX_47,
46
    &STR_PREF_REX_48,
47
    &STR_PREF_REX_49,
48
    &STR_PREF_REX_4A,
49
    &STR_PREF_REX_4B,
50
    &STR_PREF_REX_4C,
51
    &STR_PREF_REX_4D,
52
    &STR_PREF_REX_4E,
53
    &STR_PREF_REX_4F
54
};
55
56
static const ZydisPredefinedToken* const TOK_PREF_REX[16] =
57
{
58
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_40,
59
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_41,
60
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_42,
61
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_43,
62
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_44,
63
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_45,
64
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_46,
65
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_47,
66
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_48,
67
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_49,
68
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4A,
69
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4B,
70
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4C,
71
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4D,
72
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4E,
73
    (const ZydisPredefinedToken* const)&TOK_DATA_PREF_REX_4F
74
};
75
76
/* ============================================================================================== */
77
/* Helper functions                                                                               */
78
/* ============================================================================================== */
79
80
ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
81
    ZydisFormatterContext* context, const ZydisDecodedOperand* operand)
82
3.57k
{
83
3.57k
    ZYAN_ASSERT(formatter);
84
3.57k
    ZYAN_ASSERT(context);
85
3.57k
    ZYAN_ASSERT(operand);
86
87
3.57k
    ZYAN_ASSERT(operand->type == ZYDIS_OPERAND_TYPE_MEMORY);
88
3.57k
    ZYAN_ASSERT((operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
89
3.57k
                (operand->mem.type == ZYDIS_MEMOP_TYPE_AGEN) ||
90
3.57k
                (operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB));
91
92
3.57k
    if (formatter->force_memory_size)
93
2.85k
    {
94
2.85k
        return operand->size;
95
2.85k
    }
96
725
    else if (operand->mem.type == ZYDIS_MEMOP_TYPE_AGEN)
97
13
    {
98
13
        return 0;
99
13
    }
100
101
712
    if (!context->operands)
102
193
    {
103
        // Single operand formatting. We can not derive the explicit size by using the other
104
        // operands.
105
193
        return 0;
106
193
    }
107
108
519
    switch (operand->id)
109
519
    {
110
374
    case 0:
111
374
        if (context->instruction->operand_count_visible < 2)
112
77
        {
113
77
            return 0;
114
77
        }
115
297
        if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_UNUSED) ||
116
297
            (context->operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE))
117
39
        {
118
39
            return context->operands[0].size;
119
39
        }
120
258
        if (context->operands[0].size != context->operands[1].size)
121
7
        {
122
7
            return context->operands[0].size;
123
7
        }
124
251
        if ((context->operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
125
251
            (context->operands[1].visibility == ZYDIS_OPERAND_VISIBILITY_IMPLICIT) &&
126
47
            (context->operands[1].reg.value == ZYDIS_REGISTER_CL))
127
11
        {
128
11
            return context->operands[0].size;
129
11
        }
130
240
        break;
131
240
    case 1:
132
122
    case 2:
133
122
        if (context->operands[operand->id - 1].size !=
134
122
            context->operands[operand->id].size)
135
39
        {
136
39
            return context->operands[operand->id].size;
137
39
        }
138
83
        break;
139
83
    default:
140
23
        break;
141
519
    }
142
143
346
    return 0;
144
519
}
145
146
/* ============================================================================================== */
147
/* Formatter functions                                                                            */
148
/* ============================================================================================== */
149
150
/* ---------------------------------------------------------------------------------------------- */
151
/* Operands                                                                                       */
152
/* ---------------------------------------------------------------------------------------------- */
153
154
ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
155
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
156
4.55k
{
157
4.55k
    ZYAN_ASSERT(formatter);
158
4.55k
    ZYAN_ASSERT(buffer);
159
4.55k
    ZYAN_ASSERT(context);
160
161
4.55k
    return formatter->func_print_register(formatter, buffer, context, context->operand->reg.value);
162
4.55k
}
163
164
ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
165
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
166
143
{
167
143
    ZYAN_ASSERT(formatter);
168
143
    ZYAN_ASSERT(buffer);
169
143
    ZYAN_ASSERT(context);
170
171
143
    ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
172
140
    ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
173
140
        context->operand->ptr.segment, 4, formatter->hex_force_leading_number);
174
109
    ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
175
176
104
    ZyanU8 padding;
177
104
    switch (context->instruction->operand_width)
178
104
    {
179
94
    case 16:
180
94
        padding = 4;
181
94
        break;
182
10
    case 32:
183
10
        padding = 8;
184
10
        break;
185
0
    default:
186
0
        return ZYAN_STATUS_INVALID_ARGUMENT;
187
104
    }
188
189
104
    ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
190
99
    ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
191
99
        context->operand->ptr.offset , padding, formatter->hex_force_leading_number);
192
193
65
    return ZYAN_STATUS_SUCCESS;
194
99
}
195
196
ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
197
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
198
2.81k
{
199
2.81k
    ZYAN_ASSERT(formatter);
200
2.81k
    ZYAN_ASSERT(buffer);
201
2.81k
    ZYAN_ASSERT(context);
202
203
    // The immediate operand contains an address
204
2.81k
    if (context->operand->imm.is_address)
205
1.84k
    {
206
1.84k
        const ZyanBool absolute = !context->operand->imm.is_relative || 
207
1.82k
            (!formatter->force_relative_branches &&
208
1.08k
            (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE));
209
1.84k
        if (absolute)
210
1.07k
        {
211
1.07k
            return formatter->func_print_address_abs(formatter, buffer, context);
212
1.07k
        }
213
768
        return formatter->func_print_address_rel(formatter, buffer, context);
214
1.84k
    }
215
216
    // The immediate operand contains an actual ordinal value
217
969
    return formatter->func_print_imm(formatter, buffer, context);
218
2.81k
}
219
220
/* ---------------------------------------------------------------------------------------------- */
221
/* Elemental tokens                                                                               */
222
/* ---------------------------------------------------------------------------------------------- */
223
224
ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
225
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
226
1.03k
{
227
1.03k
    ZYAN_ASSERT(formatter);
228
1.03k
    ZYAN_ASSERT(buffer);
229
1.03k
    ZYAN_ASSERT(context);
230
231
1.03k
    ZyanU64 address;
232
1.03k
    ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
233
1.03k
        context->runtime_address, &address));
234
1.03k
    ZyanU8 padding = (formatter->addr_padding_absolute ==
235
1.03k
        ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_absolute;
236
1.03k
    if ((formatter->addr_padding_absolute == ZYDIS_PADDING_AUTO) &&
237
276
        (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
238
220
    {
239
220
        switch (context->instruction->address_width)
240
220
        {
241
28
        case 16:
242
28
            padding =  4;
243
28
            address = (ZyanU16)address;
244
28
            break;
245
80
        case 32:
246
80
            padding =  8;
247
80
            address = (ZyanU32)address;
248
80
            break;
249
112
        case 64:
250
112
            padding = 16;
251
112
            break;
252
0
        default:
253
0
            return ZYAN_STATUS_INVALID_ARGUMENT;
254
220
        }
255
220
    }
256
257
1.03k
    ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_ABS);
258
1.01k
    ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address, padding,
259
1.01k
        formatter->hex_force_leading_number);
260
261
647
    return ZYAN_STATUS_SUCCESS;
262
1.01k
}
263
264
ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
265
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
266
530
{
267
530
    ZYAN_ASSERT(formatter);
268
530
    ZYAN_ASSERT(buffer);
269
530
    ZYAN_ASSERT(context);
270
271
530
    ZyanU64 address;
272
530
    ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
273
274
530
    ZyanU8 padding = (formatter->addr_padding_relative ==
275
530
        ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
276
530
    if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
277
137
        (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
278
107
    {
279
107
        switch (context->instruction->address_width)
280
107
        {
281
36
        case 16:
282
36
            padding =  4;
283
36
            address = (ZyanU16)address;
284
36
            break;
285
41
        case 32:
286
41
            padding =  8;
287
41
            address = (ZyanU32)address;
288
41
            break;
289
30
        case 64:
290
30
            padding = 16;
291
30
            break;
292
0
        default:
293
0
            return ZYAN_STATUS_INVALID_ARGUMENT;
294
107
        }
295
107
    }
296
297
530
    ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_REL);
298
526
    switch (formatter->addr_signedness)
299
526
    {
300
345
    case ZYDIS_SIGNEDNESS_AUTO:
301
400
    case ZYDIS_SIGNEDNESS_SIGNED:
302
400
        ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address,
303
400
            padding, formatter->hex_force_leading_number, ZYAN_TRUE);
304
226
        break;
305
126
    case ZYDIS_SIGNEDNESS_UNSIGNED:
306
126
        ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ADD));
307
118
        ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address,
308
118
            padding, formatter->hex_force_leading_number);
309
70
        break;
310
0
    default:
311
0
        return ZYAN_STATUS_INVALID_ARGUMENT;
312
526
    }
313
314
296
    return ZYAN_STATUS_SUCCESS;
315
526
}
316
317
ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
318
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
319
954
{
320
954
    ZYAN_ASSERT(formatter);
321
954
    ZYAN_ASSERT(buffer);
322
954
    ZYAN_ASSERT(context);
323
324
954
    ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
325
326
948
    const ZyanBool is_signed =
327
948
        (formatter->imm_signedness == ZYDIS_SIGNEDNESS_SIGNED) ||
328
839
        (formatter->imm_signedness == ZYDIS_SIGNEDNESS_AUTO && (context->operand->imm.is_signed));
329
948
    if (is_signed && (context->operand->imm.value.s < 0))
330
517
    {
331
517
        ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->imm_base, &buffer->string,
332
517
            context->operand->imm.value.s, formatter->imm_padding,
333
517
            formatter->hex_force_leading_number, ZYAN_FALSE);
334
373
        return ZYAN_STATUS_SUCCESS;
335
517
    }
336
431
    ZyanU64 value;
337
431
    ZyanU8 padding = (formatter->imm_padding ==
338
431
        ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->imm_padding;
339
431
    switch (context->instruction->operand_width)
340
431
    {
341
153
    case 8:
342
153
        if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
343
27
        {
344
27
            padding =  2;
345
27
        }
346
153
        value = (ZyanU8 )context->operand->imm.value.u;
347
153
        break;
348
90
    case 16:
349
90
        if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
350
25
        {
351
25
            padding =  4;
352
25
        }
353
90
        value = (ZyanU16)context->operand->imm.value.u;
354
90
        break;
355
142
    case 32:
356
142
        if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
357
14
        {
358
14
            padding =  8;
359
14
        }
360
142
        value = (ZyanU32)context->operand->imm.value.u;
361
142
        break;
362
46
    case 64:
363
46
        if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
364
20
        {
365
20
            padding = 16;
366
20
        }
367
46
        value = (ZyanU64)context->operand->imm.value.u;
368
46
        break;
369
0
    default:
370
0
        return ZYAN_STATUS_INVALID_ARGUMENT;
371
431
    }
372
431
    ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->imm_base, &buffer->string, value, padding,
373
431
        formatter->hex_force_leading_number);
374
375
335
    return ZYAN_STATUS_SUCCESS;
376
431
}
377
378
/* ---------------------------------------------------------------------------------------------- */
379
/* Optional tokens                                                                                */
380
/* ---------------------------------------------------------------------------------------------- */
381
382
ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
383
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
384
4.27k
{
385
4.27k
    ZYAN_ASSERT(formatter);
386
4.27k
    ZYAN_ASSERT(buffer);
387
4.27k
    ZYAN_ASSERT(context);
388
389
4.27k
    ZyanBool printed_segment = ZYAN_FALSE;
390
4.27k
    switch (context->operand->mem.segment)
391
4.27k
    {
392
14
    case ZYDIS_REGISTER_ES:
393
26
    case ZYDIS_REGISTER_CS:
394
46
    case ZYDIS_REGISTER_FS:
395
62
    case ZYDIS_REGISTER_GS:
396
62
        ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
397
62
            context->operand->mem.segment));
398
49
        printed_segment = ZYAN_TRUE;
399
49
        break;
400
474
    case ZYDIS_REGISTER_SS:
401
474
        if ((formatter->force_memory_segment) ||
402
171
            (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS))
403
313
        {
404
313
            ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
405
313
                context->operand->mem.segment));
406
296
            printed_segment = ZYAN_TRUE;
407
296
        }
408
457
        break;
409
3.73k
    case ZYDIS_REGISTER_DS:
410
3.73k
        if ((formatter->force_memory_segment) ||
411
1.02k
            (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_DS))
412
2.71k
        {
413
2.71k
            ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
414
2.71k
                context->operand->mem.segment));
415
2.63k
            printed_segment = ZYAN_TRUE;
416
2.63k
        }
417
3.65k
        break;
418
3.65k
    default:
419
0
        break;
420
4.27k
    }
421
4.15k
    if (printed_segment)
422
2.98k
    {
423
2.98k
        ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
424
2.91k
    }
425
426
4.08k
    return ZYAN_STATUS_SUCCESS;
427
4.15k
}
428
429
ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
430
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
431
5.80k
{
432
5.80k
    ZYAN_ASSERT(formatter);
433
5.80k
    ZYAN_ASSERT(buffer);
434
5.80k
    ZYAN_ASSERT(context);
435
436
5.80k
    if (formatter->detailed_prefixes)
437
3.77k
    {
438
5.36k
        for (ZyanU8 i = 0; i < context->instruction->raw.prefix_count; ++i)
439
1.65k
        {
440
1.65k
            const ZyanU8 value = context->instruction->raw.prefixes[i].value;
441
1.65k
            switch (context->instruction->raw.prefixes[i].type)
442
1.65k
            {
443
1.16k
            case ZYDIS_PREFIX_TYPE_IGNORED:
444
1.19k
            case ZYDIS_PREFIX_TYPE_MANDATORY:
445
1.19k
            {
446
1.19k
                if ((value & 0xF0) == 0x40)
447
435
                {
448
435
                    if (buffer->is_token_list)
449
216
                    {
450
                        // TODO: Case
451
216
                        ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer,
452
216
                            TOK_PREF_REX[value & 0x0F]));
453
216
                    } else
454
219
                    {
455
219
                        ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string,
456
219
                            STR_PREF_REX[value & 0x0F], formatter->case_prefixes));
457
219
                    }
458
435
                } else
459
755
                {
460
755
                    switch (value)
461
755
                    {
462
102
                    case 0xF0:
463
102
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
464
98
                        break;
465
81
                    case 0x2E:
466
81
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_CS, formatter->case_prefixes);
467
77
                        break;
468
61
                    case 0x36:
469
61
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_SS, formatter->case_prefixes);
470
56
                        break;
471
43
                    case 0x3E:
472
43
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_DS, formatter->case_prefixes);
473
40
                        break;
474
96
                    case 0x26:
475
96
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_ES, formatter->case_prefixes);
476
89
                        break;
477
78
                    case 0x64:
478
78
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_FS, formatter->case_prefixes);
479
73
                        break;
480
62
                    case 0x65:
481
62
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_GS, formatter->case_prefixes);
482
57
                        break;
483
232
                    default:
484
232
                        ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_PREFIX);
485
229
                        ZYAN_CHECK(ZydisStringAppendHexU(&buffer->string, value, 0,
486
229
                            formatter->hex_force_leading_number, formatter->hex_uppercase,
487
229
                            ZYAN_NULL, ZYAN_NULL));
488
224
                        ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_WHITESPACE);
489
221
                        ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_WHITESPACE));
490
214
                        break;
491
755
                    }
492
755
                }
493
1.13k
                break;
494
1.19k
            }
495
1.13k
            case ZYDIS_PREFIX_TYPE_EFFECTIVE:
496
469
                switch (value)
497
469
                {
498
76
                case 0xF0:
499
76
                    ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
500
69
                    break;
501
72
                case 0xF2:
502
72
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
503
29
                    {
504
29
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
505
26
                    }
506
69
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
507
0
                    {
508
0
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
509
0
                    }
510
511
69
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
512
43
                    {
513
43
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
514
37
                    }
515
63
                    break;
516
63
                case 0xF3:
517
35
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
518
35
                    {
519
35
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
520
32
                    }
521
32
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
522
0
                    {
523
0
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
524
0
                    }
525
32
                    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
526
0
                    {
527
0
                        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
528
0
                    }
529
32
                    break;
530
286
                default:
531
286
                    break;
532
469
                }
533
450
                break;
534
450
            default:
535
0
                return ZYAN_STATUS_INVALID_ARGUMENT;
536
1.65k
            }
537
1.65k
        }
538
3.70k
        return ZYAN_STATUS_SUCCESS;
539
3.77k
    }
540
541
2.02k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
542
31
    {
543
31
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
544
28
    }
545
2.02k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
546
25
    {
547
25
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
548
21
    }
549
550
2.02k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
551
40
    {
552
40
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
553
35
    }
554
555
2.01k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
556
31
    {
557
31
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
558
29
    }
559
560
2.01k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK)
561
36
    {
562
36
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_NOTRACK, formatter->case_prefixes);
563
31
    }
564
565
2.00k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
566
34
    {
567
34
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
568
31
        return ZYAN_STATUS_SUCCESS;
569
34
    }
570
1.97k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
571
8
    {
572
8
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
573
4
        return ZYAN_STATUS_SUCCESS;
574
8
    }
575
1.96k
    if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
576
5
    {
577
5
        ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
578
3
        return ZYAN_STATUS_SUCCESS;
579
5
    }
580
581
1.96k
    return ZYAN_STATUS_SUCCESS;
582
1.96k
}
583
584
ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
585
    ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator)
586
6.12k
{
587
6.12k
    ZYAN_ASSERT(formatter);
588
6.12k
    ZYAN_ASSERT(buffer);
589
6.12k
    ZYAN_ASSERT(context);
590
591
#if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
592
    ZYAN_UNUSED(formatter);
593
    ZYAN_UNUSED(buffer);
594
    ZYAN_UNUSED(context);
595
#endif
596
597
6.12k
    switch (decorator)
598
6.12k
    {
599
254
    case ZYDIS_DECORATOR_MASK:
600
254
    {
601
254
#if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
602
254
        if (context->instruction->avx.mask.reg != ZYDIS_REGISTER_K0)
603
228
        {
604
228
            if (buffer->is_token_list)
605
94
            {
606
94
                ZYDIS_BUFFER_APPEND(buffer, DECO_BEGIN);
607
85
                ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
608
85
                    context->instruction->avx.mask.reg));
609
74
                ZYDIS_BUFFER_APPEND(buffer, DECO_END);
610
68
            } else
611
134
            {
612
134
                ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_BEGIN));
613
129
                ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
614
129
                    context->instruction->avx.mask.reg));
615
119
                ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_END));
616
119
            }
617
618
            // Only print the zeroing decorator, if the instruction is not a "zeroing masking only"
619
            // instruction (e.g. `vcmpsd`)
620
184
            if ((context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_ZEROING ||
621
140
                 context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_CONTROL_ZEROING) &&
622
47
                (context->instruction->raw.evex.z))
623
42
            {
624
42
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_ZERO, formatter->case_decorators);
625
37
            }
626
184
        }
627
205
#endif
628
205
        break;
629
254
    }
630
241
    case ZYDIS_DECORATOR_BC:
631
241
#if !defined(ZYDIS_DISABLE_AVX512)
632
241
        if (!context->instruction->avx.broadcast.is_static)
633
219
        {
634
219
            switch (context->instruction->avx.broadcast.mode)
635
219
            {
636
152
            case ZYDIS_BROADCAST_MODE_NONE:
637
152
                break;
638
9
            case ZYDIS_BROADCAST_MODE_1_TO_2:
639
9
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO2, formatter->case_decorators);
640
7
                break;
641
6
            case ZYDIS_BROADCAST_MODE_1_TO_4:
642
6
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO4, formatter->case_decorators);
643
4
                break;
644
19
            case ZYDIS_BROADCAST_MODE_1_TO_8:
645
19
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO8, formatter->case_decorators);
646
12
                break;
647
11
            case ZYDIS_BROADCAST_MODE_1_TO_16:
648
11
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO16, formatter->case_decorators);
649
7
                break;
650
7
            case ZYDIS_BROADCAST_MODE_1_TO_32:
651
7
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO32, formatter->case_decorators);
652
5
                break;
653
0
            case ZYDIS_BROADCAST_MODE_1_TO_64:
654
0
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO64, formatter->case_decorators);
655
0
                break;
656
8
            case ZYDIS_BROADCAST_MODE_4_TO_8:
657
8
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO8, formatter->case_decorators);
658
6
                break;
659
7
            case ZYDIS_BROADCAST_MODE_4_TO_16:
660
7
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO16, formatter->case_decorators);
661
5
                break;
662
0
            case ZYDIS_BROADCAST_MODE_8_TO_16:
663
0
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_8TO16, formatter->case_decorators);
664
0
                break;
665
0
            default:
666
0
                return ZYAN_STATUS_INVALID_ARGUMENT;
667
219
            }
668
219
        }
669
220
#endif
670
220
        break;
671
220
    case ZYDIS_DECORATOR_RC:
672
171
#if !defined(ZYDIS_DISABLE_AVX512)
673
171
        if (context->instruction->avx.has_sae)
674
36
        {
675
36
            switch (context->instruction->avx.rounding.mode)
676
36
            {
677
7
            case ZYDIS_ROUNDING_MODE_NONE:
678
7
                break;
679
6
            case ZYDIS_ROUNDING_MODE_RN:
680
6
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN_SAE, formatter->case_decorators);
681
3
                break;
682
8
            case ZYDIS_ROUNDING_MODE_RD:
683
8
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD_SAE, formatter->case_decorators);
684
5
                break;
685
10
            case ZYDIS_ROUNDING_MODE_RU:
686
10
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU_SAE, formatter->case_decorators);
687
7
                break;
688
5
            case ZYDIS_ROUNDING_MODE_RZ:
689
5
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ_SAE, formatter->case_decorators);
690
3
                break;
691
0
            default:
692
0
                return ZYAN_STATUS_INVALID_ARGUMENT;
693
36
            }
694
36
        } else
695
135
        {
696
135
            switch (context->instruction->avx.rounding.mode)
697
135
            {
698
115
            case ZYDIS_ROUNDING_MODE_NONE:
699
115
                break;
700
5
            case ZYDIS_ROUNDING_MODE_RN:
701
5
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN, formatter->case_decorators);
702
3
                break;
703
5
            case ZYDIS_ROUNDING_MODE_RD:
704
5
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD, formatter->case_decorators);
705
3
                break;
706
5
            case ZYDIS_ROUNDING_MODE_RU:
707
5
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU, formatter->case_decorators);
708
3
                break;
709
5
            case ZYDIS_ROUNDING_MODE_RZ:
710
5
                ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ, formatter->case_decorators);
711
3
                break;
712
0
            default:
713
0
                return ZYAN_STATUS_INVALID_ARGUMENT;
714
135
            }
715
135
        }
716
152
#endif
717
152
        break;
718
152
    case ZYDIS_DECORATOR_SAE:
719
152
#if !defined(ZYDIS_DISABLE_AVX512)
720
152
        if (context->instruction->avx.has_sae && !context->instruction->avx.rounding.mode)
721
7
        {
722
7
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SAE, formatter->case_decorators);
723
5
        }
724
150
#endif
725
150
        break;
726
150
    case ZYDIS_DECORATOR_SWIZZLE:
727
102
#if !defined(ZYDIS_DISABLE_KNC)
728
102
        switch (context->instruction->avx.swizzle.mode)
729
102
        {
730
57
        case ZYDIS_SWIZZLE_MODE_NONE:
731
60
        case ZYDIS_SWIZZLE_MODE_DCBA:
732
            // Nothing to do here
733
60
            break;
734
5
        case ZYDIS_SWIZZLE_MODE_CDAB:
735
5
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CDAB, formatter->case_decorators);
736
3
            break;
737
7
        case ZYDIS_SWIZZLE_MODE_BADC:
738
7
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BADC, formatter->case_decorators);
739
5
            break;
740
5
        case ZYDIS_SWIZZLE_MODE_DACB:
741
5
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DACB, formatter->case_decorators);
742
3
            break;
743
5
        case ZYDIS_SWIZZLE_MODE_AAAA:
744
5
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_AAAA, formatter->case_decorators);
745
3
            break;
746
7
        case ZYDIS_SWIZZLE_MODE_BBBB:
747
7
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BBBB, formatter->case_decorators);
748
4
            break;
749
7
        case ZYDIS_SWIZZLE_MODE_CCCC:
750
7
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CCCC, formatter->case_decorators);
751
4
            break;
752
6
        case ZYDIS_SWIZZLE_MODE_DDDD:
753
6
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DDDD, formatter->case_decorators);
754
4
            break;
755
0
        default:
756
0
            return ZYAN_STATUS_INVALID_ARGUMENT;
757
102
        }
758
86
#endif
759
86
        break;
760
94
    case ZYDIS_DECORATOR_CONVERSION:
761
94
#if !defined(ZYDIS_DISABLE_KNC)
762
94
        switch (context->instruction->avx.conversion.mode)
763
94
        {
764
41
        case ZYDIS_CONVERSION_MODE_NONE:
765
41
            break;
766
11
        case ZYDIS_CONVERSION_MODE_FLOAT16:
767
11
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_FLOAT16, formatter->case_decorators);
768
7
            break;
769
9
        case ZYDIS_CONVERSION_MODE_SINT8:
770
9
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT8, formatter->case_decorators);
771
6
            break;
772
11
        case ZYDIS_CONVERSION_MODE_UINT8:
773
11
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT8, formatter->case_decorators);
774
9
            break;
775
11
        case ZYDIS_CONVERSION_MODE_SINT16:
776
11
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT16, formatter->case_decorators);
777
6
            break;
778
11
        case ZYDIS_CONVERSION_MODE_UINT16:
779
11
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT16, formatter->case_decorators);
780
8
            break;
781
0
        default:
782
0
            return ZYAN_STATUS_INVALID_ARGUMENT;
783
94
        }
784
77
#endif
785
77
        break;
786
77
    case ZYDIS_DECORATOR_EH:
787
77
#if !defined(ZYDIS_DISABLE_KNC)
788
77
        if (context->instruction->avx.has_eviction_hint)
789
46
        {
790
46
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_EH, formatter->case_decorators);
791
40
        }
792
71
#endif
793
71
        break;
794
2.64k
    case ZYDIS_DECORATOR_APX_NF:
795
2.64k
#if !defined(ZYDIS_DISABLE_AVX512)
796
2.64k
        if (context->instruction->apx.has_nf)
797
29
        {
798
29
            ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_NF, formatter->case_decorators);
799
26
        }
800
2.64k
#endif
801
2.64k
        break;
802
2.64k
    case ZYDIS_DECORATOR_APX_DFV:
803
2.39k
#if !defined(ZYDIS_DISABLE_AVX512)
804
2.39k
        if (context->instruction->apx.scc != ZYDIS_SCC_NONE)
805
89
        {
806
89
            switch (context->instruction->apx.default_flags)
807
89
            {
808
4
            case 0x0: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_0, formatter->case_decorators); break;
809
6
            case 0x1: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_1, formatter->case_decorators); break;
810
8
            case 0x2: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_2, formatter->case_decorators); break;
811
4
            case 0x3: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_3, formatter->case_decorators); break;
812
5
            case 0x4: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_4, formatter->case_decorators); break;
813
6
            case 0x5: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_5, formatter->case_decorators); break;
814
6
            case 0x6: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_6, formatter->case_decorators); break;
815
5
            case 0x7: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_7, formatter->case_decorators); break;
816
7
            case 0x8: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_8, formatter->case_decorators); break;
817
6
            case 0x9: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_9, formatter->case_decorators); break;
818
6
            case 0xA: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_A, formatter->case_decorators); break;
819
4
            case 0xB: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_B, formatter->case_decorators); break;
820
8
            case 0xC: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_C, formatter->case_decorators); break;
821
4
            case 0xD: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_D, formatter->case_decorators); break;
822
4
            case 0xE: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_E, formatter->case_decorators); break;
823
6
            case 0xF: ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DFV_F, formatter->case_decorators); break;
824
0
            default:
825
0
                return ZYAN_STATUS_INVALID_ARGUMENT;
826
89
            }
827
89
        }
828
2.34k
#endif
829
2.34k
        break;
830
2.34k
    default:
831
0
        return ZYAN_STATUS_INVALID_ARGUMENT;
832
6.12k
    }
833
834
5.95k
    return ZYAN_STATUS_SUCCESS;
835
6.12k
}
836
837
/* ---------------------------------------------------------------------------------------------- */
838
839
/* ============================================================================================== */