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/Zydis/Internal/FormatterBase.h"
28 #include "zydis/Zydis/Utils.h"
29 
30 /* ============================================================================================== */
31 /* Constants                                                                                      */
32 /* ============================================================================================== */
33 
34 #include "zydis/Zydis/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 
ZydisFormatterHelperGetExplicitSize(const ZydisFormatter * formatter,ZydisFormatterContext * context,ZyanU8 memop_id)80 ZyanU32 ZydisFormatterHelperGetExplicitSize(const ZydisFormatter* formatter,
81     ZydisFormatterContext* context, ZyanU8 memop_id)
82 {
83     ZYAN_ASSERT(formatter);
84     ZYAN_ASSERT(context);
85     ZYAN_ASSERT(memop_id < context->instruction->operand_count);
86 
87     const ZydisDecodedOperand* const operand = &context->instruction->operands[memop_id];
88     ZYAN_ASSERT(operand->type == ZYDIS_OPERAND_TYPE_MEMORY);
89     ZYAN_ASSERT(operand->mem.type == ZYDIS_MEMOP_TYPE_MEM);
90 
91     if (formatter->force_memory_size)
92     {
93         return operand->size;
94     }
95 
96     switch (operand->id)
97     {
98     case 0:
99         if ((context->instruction->operands[1].type == ZYDIS_OPERAND_TYPE_UNUSED) ||
100             (context->instruction->operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE))
101         {
102             return context->instruction->operands[0].size;
103         }
104         if (context->instruction->operands[0].size != context->instruction->operands[1].size)
105         {
106             return context->instruction->operands[0].size;
107         }
108         if ((context->instruction->operands[1].type == ZYDIS_OPERAND_TYPE_REGISTER) &&
109             (context->instruction->operands[1].visibility == ZYDIS_OPERAND_VISIBILITY_IMPLICIT) &&
110             (context->instruction->operands[1].reg.value == ZYDIS_REGISTER_CL))
111         {
112             return context->instruction->operands[0].size;
113         }
114         break;
115     case 1:
116     case 2:
117         if (context->instruction->operands[operand->id - 1].size !=
118             context->instruction->operands[operand->id].size)
119         {
120             return context->instruction->operands[operand->id].size;
121         }
122         break;
123     default:
124         break;
125     }
126 
127     return 0;
128 }
129 
130 /* ============================================================================================== */
131 /* Formatter functions                                                                            */
132 /* ============================================================================================== */
133 
134 /* ---------------------------------------------------------------------------------------------- */
135 /* Operands                                                                                       */
136 /* ---------------------------------------------------------------------------------------------- */
137 
ZydisFormatterBaseFormatOperandREG(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)138 ZyanStatus ZydisFormatterBaseFormatOperandREG(const ZydisFormatter* formatter,
139     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
140 {
141     ZYAN_ASSERT(formatter);
142     ZYAN_ASSERT(buffer);
143     ZYAN_ASSERT(context);
144 
145     return formatter->func_print_register(formatter, buffer, context, context->operand->reg.value);
146 }
147 
ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)148 ZyanStatus ZydisFormatterBaseFormatOperandPTR(const ZydisFormatter* formatter,
149     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
150 {
151     ZYAN_ASSERT(formatter);
152     ZYAN_ASSERT(buffer);
153     ZYAN_ASSERT(context);
154 
155     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
156     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
157         context->operand->ptr.segment, 4);
158     ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
159     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
160     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string,
161         context->operand->ptr.offset , 8);
162 
163     return ZYAN_STATUS_SUCCESS;
164 }
165 
ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)166 ZyanStatus ZydisFormatterBaseFormatOperandIMM(const ZydisFormatter* formatter,
167     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
168 {
169     ZYAN_ASSERT(formatter);
170     ZYAN_ASSERT(buffer);
171     ZYAN_ASSERT(context);
172 
173     // The immediate operand contains an address
174     if (context->operand->imm.is_relative)
175     {
176         const ZyanBool absolute = !formatter->force_relative_branches &&
177             (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
178         if (absolute)
179         {
180             return formatter->func_print_address_abs(formatter, buffer, context);
181         }
182         return formatter->func_print_address_rel(formatter, buffer, context);
183     }
184 
185     // The immediate operand contains an actual ordinal value
186     return formatter->func_print_imm(formatter, buffer, context);
187 }
188 
189 /* ---------------------------------------------------------------------------------------------- */
190 /* Elemental tokens                                                                               */
191 /* ---------------------------------------------------------------------------------------------- */
192 
ZydisFormatterBasePrintAddressABS(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)193 ZyanStatus ZydisFormatterBasePrintAddressABS(const ZydisFormatter* formatter,
194     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
195 {
196     ZYAN_ASSERT(formatter);
197     ZYAN_ASSERT(buffer);
198     ZYAN_ASSERT(context);
199 
200     ZyanU64 address;
201     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand,
202         context->runtime_address, &address));
203     ZyanU8 padding = (formatter->addr_padding_absolute ==
204         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_absolute;
205     if ((formatter->addr_padding_absolute == ZYDIS_PADDING_AUTO) &&
206         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
207     {
208         switch (context->instruction->stack_width)
209         {
210         case 16:
211             padding =  4;
212             address = (ZyanU16)address;
213             break;
214         case 32:
215             padding =  8;
216             address = (ZyanU32)address;
217             break;
218         case 64:
219             padding = 16;
220             break;
221         default:
222             return ZYAN_STATUS_INVALID_ARGUMENT;
223         }
224     }
225 
226     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_ABS);
227     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address, padding);
228 
229     return ZYAN_STATUS_SUCCESS;
230 }
231 
ZydisFormatterBasePrintAddressREL(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)232 ZyanStatus ZydisFormatterBasePrintAddressREL(const ZydisFormatter* formatter,
233     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
234 {
235     ZYAN_ASSERT(formatter);
236     ZYAN_ASSERT(buffer);
237     ZYAN_ASSERT(context);
238 
239     ZyanU64 address;
240     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
241 
242     ZyanU8 padding = (formatter->addr_padding_relative ==
243         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
244     if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
245         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
246     {
247         switch (context->instruction->stack_width)
248         {
249         case 16:
250             padding =  4;
251             address = (ZyanU16)address;
252             break;
253         case 32:
254             padding =  8;
255             address = (ZyanU32)address;
256             break;
257         case 64:
258             padding = 16;
259             break;
260         default:
261             return ZYAN_STATUS_INVALID_ARGUMENT;
262         }
263     }
264 
265     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_ADDRESS_REL);
266     switch (formatter->addr_signedness)
267     {
268     case ZYDIS_SIGNEDNESS_AUTO:
269     case ZYDIS_SIGNEDNESS_SIGNED:
270         ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address,
271             padding, ZYAN_TRUE);
272         break;
273     case ZYDIS_SIGNEDNESS_UNSIGNED:
274         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_ADD));
275         ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->addr_base, &buffer->string, address,
276             padding);
277         break;
278     default:
279         return ZYAN_STATUS_INVALID_ARGUMENT;
280     }
281 
282     return ZYAN_STATUS_SUCCESS;
283 }
284 
ZydisFormatterBasePrintIMM(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)285 ZyanStatus ZydisFormatterBasePrintIMM(const ZydisFormatter* formatter,
286     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
287 {
288     ZYAN_ASSERT(formatter);
289     ZYAN_ASSERT(buffer);
290     ZYAN_ASSERT(context);
291 
292     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
293 
294     const ZyanBool is_signed =
295         (formatter->imm_signedness == ZYDIS_SIGNEDNESS_SIGNED) ||
296         (formatter->imm_signedness == ZYDIS_SIGNEDNESS_AUTO && (context->operand->imm.is_signed));
297     if (is_signed && (context->operand->imm.value.s < 0))
298     {
299         ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->imm_base, &buffer->string,
300             context->operand->imm.value.s, formatter->imm_padding, ZYAN_FALSE);
301         return ZYAN_STATUS_SUCCESS;
302     }
303     ZyanU64 value;
304     ZyanU8 padding = (formatter->imm_padding ==
305         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->imm_padding;
306     switch (context->instruction->operand_width)
307     {
308     case 8:
309         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
310         {
311             padding =  2;
312         }
313         value = (ZyanU8 )context->operand->imm.value.u;
314         break;
315     case 16:
316         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
317         {
318             padding =  4;
319         }
320         value = (ZyanU16)context->operand->imm.value.u;
321         break;
322     case 32:
323         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
324         {
325             padding =  8;
326         }
327         value = (ZyanU32)context->operand->imm.value.u;
328         break;
329     case 64:
330         if (formatter->imm_padding == ZYDIS_PADDING_AUTO)
331         {
332             padding = 16;
333         }
334         value = (ZyanU64)context->operand->imm.value.u;
335         break;
336     default:
337         return ZYAN_STATUS_INVALID_ARGUMENT;
338     }
339     ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->imm_base, &buffer->string, value, padding);
340 
341     return ZYAN_STATUS_SUCCESS;
342 }
343 
344 /* ---------------------------------------------------------------------------------------------- */
345 /* Optional tokens                                                                                */
346 /* ---------------------------------------------------------------------------------------------- */
347 
ZydisFormatterBasePrintSegment(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)348 ZyanStatus ZydisFormatterBasePrintSegment(const ZydisFormatter* formatter,
349     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
350 {
351     ZYAN_ASSERT(formatter);
352     ZYAN_ASSERT(buffer);
353     ZYAN_ASSERT(context);
354 
355     ZyanBool printed_segment = ZYAN_FALSE;
356     switch (context->operand->mem.segment)
357     {
358     case ZYDIS_REGISTER_ES:
359     case ZYDIS_REGISTER_CS:
360     case ZYDIS_REGISTER_FS:
361     case ZYDIS_REGISTER_GS:
362         ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
363             context->operand->mem.segment));
364         printed_segment = ZYAN_TRUE;
365         break;
366     case ZYDIS_REGISTER_SS:
367         if ((formatter->force_memory_segment) ||
368             (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS))
369         {
370             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
371                 context->operand->mem.segment));
372             printed_segment = ZYAN_TRUE;
373         }
374         break;
375     case ZYDIS_REGISTER_DS:
376         if ((formatter->force_memory_segment) ||
377             (context->instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_DS))
378         {
379             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
380                 context->operand->mem.segment));
381             printed_segment = ZYAN_TRUE;
382         }
383         break;
384     default:
385         break;
386     }
387     if (printed_segment)
388     {
389         ZYDIS_BUFFER_APPEND(buffer, DELIM_SEGMENT);
390     }
391 
392     return ZYAN_STATUS_SUCCESS;
393 }
394 
ZydisFormatterBasePrintPrefixes(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context)395 ZyanStatus ZydisFormatterBasePrintPrefixes(const ZydisFormatter* formatter,
396     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
397 {
398     ZYAN_ASSERT(formatter);
399     ZYAN_ASSERT(buffer);
400     ZYAN_ASSERT(context);
401 
402     if (formatter->detailed_prefixes)
403     {
404         for (ZyanU8 i = 0; i < context->instruction->raw.prefix_count; ++i)
405         {
406             const ZyanU8 value = context->instruction->raw.prefixes[i].value;
407             switch (context->instruction->raw.prefixes[i].type)
408             {
409             case ZYDIS_PREFIX_TYPE_IGNORED:
410             case ZYDIS_PREFIX_TYPE_MANDATORY:
411             {
412                 if ((value & 0xF0) == 0x40)
413                 {
414                     if (buffer->is_token_list)
415                     {
416                         // TODO: Case
417                         ZYAN_CHECK(ZydisFormatterBufferAppendPredefined(buffer,
418                             TOK_PREF_REX[value & 0x0F]));
419                     } else
420                     {
421                         ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string,
422                             STR_PREF_REX[value & 0x0F], formatter->case_prefixes));
423                     }
424                 } else
425                 {
426                     switch (value)
427                     {
428                     case 0xF0:
429                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
430                         break;
431                     case 0x2E:
432                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_CS, formatter->case_prefixes);
433                         break;
434                     case 0x36:
435                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_SS, formatter->case_prefixes);
436                         break;
437                     case 0x3E:
438                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_DS, formatter->case_prefixes);
439                         break;
440                     case 0x26:
441                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_ES, formatter->case_prefixes);
442                         break;
443                     case 0x64:
444                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_FS, formatter->case_prefixes);
445                         break;
446                     case 0x65:
447                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_SEG_GS, formatter->case_prefixes);
448                         break;
449                     default:
450                         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_PREFIX);
451                         ZYAN_CHECK(ZydisStringAppendHexU(&buffer->string, value, 0,
452                             formatter->hex_uppercase, ZYAN_NULL, ZYAN_NULL));
453                         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_WHITESPACE);
454                         ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_WHITESPACE));
455                         break;
456                     }
457                 }
458                 break;
459             }
460             case ZYDIS_PREFIX_TYPE_EFFECTIVE:
461                 switch (value)
462                 {
463                 case 0xF0:
464                     ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
465                     break;
466                 case 0xF2:
467                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
468                     {
469                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
470                     }
471                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
472                     {
473                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
474                     }
475 
476                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
477                     {
478                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
479                     }
480                     break;
481                 case 0xF3:
482                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
483                     {
484                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
485                     }
486                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
487                     {
488                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
489                     }
490                     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
491                     {
492                         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
493                     }
494                     break;
495                 default:
496                     break;
497                 }
498                 break;
499             default:
500                 return ZYAN_STATUS_INVALID_ARGUMENT;
501             }
502         }
503         return ZYAN_STATUS_SUCCESS;
504     }
505 
506     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XACQUIRE)
507     {
508         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XACQUIRE, formatter->case_prefixes);
509     }
510     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_XRELEASE)
511     {
512         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_XRELEASE, formatter->case_prefixes);
513     }
514 
515     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK)
516     {
517         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_LOCK, formatter->case_prefixes);
518         return ZYAN_STATUS_SUCCESS;
519     }
520 
521     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REP)
522     {
523         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REP, formatter->case_prefixes);
524         return ZYAN_STATUS_SUCCESS;
525     }
526     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPE)
527     {
528         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPE, formatter->case_prefixes);
529         return ZYAN_STATUS_SUCCESS;
530     }
531     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_REPNE)
532     {
533         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_REPNE, formatter->case_prefixes);
534         return ZYAN_STATUS_SUCCESS;
535     }
536 
537     if (context->instruction->attributes & ZYDIS_ATTRIB_HAS_BND)
538     {
539         ZYDIS_BUFFER_APPEND_CASE(buffer, PREF_BND, formatter->case_prefixes);
540         return ZYAN_STATUS_SUCCESS;
541     }
542 
543     return ZYAN_STATUS_SUCCESS;
544 }
545 
ZydisFormatterBasePrintDecorator(const ZydisFormatter * formatter,ZydisFormatterBuffer * buffer,ZydisFormatterContext * context,ZydisDecorator decorator)546 ZyanStatus ZydisFormatterBasePrintDecorator(const ZydisFormatter* formatter,
547     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisDecorator decorator)
548 {
549     ZYAN_ASSERT(formatter);
550     ZYAN_ASSERT(buffer);
551     ZYAN_ASSERT(context);
552 
553 #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
554     ZYAN_UNUSED(formatter);
555     ZYAN_UNUSED(buffer);
556     ZYAN_UNUSED(context);
557 #endif
558 
559     switch (decorator)
560     {
561     case ZYDIS_DECORATOR_MASK:
562     {
563 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
564         if (context->instruction->avx.mask.reg != ZYDIS_REGISTER_K0)
565         {
566             if (buffer->is_token_list)
567             {
568                 ZYDIS_BUFFER_APPEND(buffer, DECO_BEGIN);
569                 ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
570                     context->instruction->avx.mask.reg));
571                 ZYDIS_BUFFER_APPEND(buffer, DECO_END);
572             } else
573             {
574                 ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_BEGIN));
575                 ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
576                     context->instruction->avx.mask.reg));
577                 ZYAN_CHECK(ZydisStringAppendShort(&buffer->string, &STR_DECO_END));
578             }
579 
580             // Only print the zeroing decorator, if the instruction is not a "zeroing masking only"
581             // instruction (e.g. `vcmpsd`)
582             if ((context->instruction->avx.mask.mode == ZYDIS_MASK_MODE_ZEROING) &&
583                 (context->instruction->raw.evex.z))
584             {
585                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_ZERO, formatter->case_decorators);
586             }
587         }
588 #endif
589         break;
590     }
591     case ZYDIS_DECORATOR_BC:
592 #if !defined(ZYDIS_DISABLE_AVX512)
593         if (!context->instruction->avx.broadcast.is_static)
594         {
595             switch (context->instruction->avx.broadcast.mode)
596             {
597             case ZYDIS_BROADCAST_MODE_INVALID:
598                 break;
599             case ZYDIS_BROADCAST_MODE_1_TO_2:
600                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO2, formatter->case_decorators);
601                 break;
602             case ZYDIS_BROADCAST_MODE_1_TO_4:
603                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO4, formatter->case_decorators);
604                 break;
605             case ZYDIS_BROADCAST_MODE_1_TO_8:
606                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO8, formatter->case_decorators);
607                 break;
608             case ZYDIS_BROADCAST_MODE_1_TO_16:
609                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_1TO16, formatter->case_decorators);
610                 break;
611             case ZYDIS_BROADCAST_MODE_4_TO_8:
612                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO8, formatter->case_decorators);
613                 break;
614             case ZYDIS_BROADCAST_MODE_4_TO_16:
615                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_4TO16, formatter->case_decorators);
616                 break;
617             default:
618                 return ZYAN_STATUS_INVALID_ARGUMENT;
619             }
620         }
621 #endif
622         break;
623     case ZYDIS_DECORATOR_RC:
624 #if !defined(ZYDIS_DISABLE_AVX512)
625         if (context->instruction->avx.has_sae)
626         {
627             switch (context->instruction->avx.rounding.mode)
628             {
629             case ZYDIS_ROUNDING_MODE_INVALID:
630                 break;
631             case ZYDIS_ROUNDING_MODE_RN:
632                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN_SAE, formatter->case_decorators);
633                 break;
634             case ZYDIS_ROUNDING_MODE_RD:
635                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD_SAE, formatter->case_decorators);
636                 break;
637             case ZYDIS_ROUNDING_MODE_RU:
638                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU_SAE, formatter->case_decorators);
639                 break;
640             case ZYDIS_ROUNDING_MODE_RZ:
641                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ_SAE, formatter->case_decorators);
642                 break;
643             default:
644                 return ZYAN_STATUS_INVALID_ARGUMENT;
645             }
646         } else
647         {
648             switch (context->instruction->avx.rounding.mode)
649             {
650             case ZYDIS_ROUNDING_MODE_INVALID:
651                 break;
652             case ZYDIS_ROUNDING_MODE_RN:
653                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RN, formatter->case_decorators);
654                 break;
655             case ZYDIS_ROUNDING_MODE_RD:
656                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RD, formatter->case_decorators);
657                 break;
658             case ZYDIS_ROUNDING_MODE_RU:
659                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RU, formatter->case_decorators);
660                 break;
661             case ZYDIS_ROUNDING_MODE_RZ:
662                 ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_RZ, formatter->case_decorators);
663                 break;
664             default:
665                 return ZYAN_STATUS_INVALID_ARGUMENT;
666             }
667         }
668 #endif
669         break;
670     case ZYDIS_DECORATOR_SAE:
671 #if !defined(ZYDIS_DISABLE_AVX512)
672         if (context->instruction->avx.has_sae && !context->instruction->avx.rounding.mode)
673         {
674             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SAE, formatter->case_decorators);
675         }
676 #endif
677         break;
678     case ZYDIS_DECORATOR_SWIZZLE:
679 #if !defined(ZYDIS_DISABLE_KNC)
680         switch (context->instruction->avx.swizzle.mode)
681         {
682         case ZYDIS_SWIZZLE_MODE_INVALID:
683         case ZYDIS_SWIZZLE_MODE_DCBA:
684             // Nothing to do here
685             break;
686         case ZYDIS_SWIZZLE_MODE_CDAB:
687             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CDAB, formatter->case_decorators);
688             break;
689         case ZYDIS_SWIZZLE_MODE_BADC:
690             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BADC, formatter->case_decorators);
691             break;
692         case ZYDIS_SWIZZLE_MODE_DACB:
693             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DACB, formatter->case_decorators);
694             break;
695         case ZYDIS_SWIZZLE_MODE_AAAA:
696             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_AAAA, formatter->case_decorators);
697             break;
698         case ZYDIS_SWIZZLE_MODE_BBBB:
699             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_BBBB, formatter->case_decorators);
700             break;
701         case ZYDIS_SWIZZLE_MODE_CCCC:
702             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_CCCC, formatter->case_decorators);
703             break;
704         case ZYDIS_SWIZZLE_MODE_DDDD:
705             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_DDDD, formatter->case_decorators);
706             break;
707         default:
708             return ZYAN_STATUS_INVALID_ARGUMENT;
709         }
710 #endif
711         break;
712     case ZYDIS_DECORATOR_CONVERSION:
713 #if !defined(ZYDIS_DISABLE_KNC)
714         switch (context->instruction->avx.conversion.mode)
715         {
716         case ZYDIS_CONVERSION_MODE_INVALID:
717             break;
718         case ZYDIS_CONVERSION_MODE_FLOAT16:
719             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_FLOAT16, formatter->case_decorators);
720             break;
721         case ZYDIS_CONVERSION_MODE_SINT8:
722             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT8, formatter->case_decorators);
723             break;
724         case ZYDIS_CONVERSION_MODE_UINT8:
725             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT8, formatter->case_decorators);
726             break;
727         case ZYDIS_CONVERSION_MODE_SINT16:
728             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_SINT16, formatter->case_decorators);
729             break;
730         case ZYDIS_CONVERSION_MODE_UINT16:
731             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_UINT16, formatter->case_decorators);
732             break;
733         default:
734             return ZYAN_STATUS_INVALID_ARGUMENT;
735         }
736 #endif
737         break;
738     case ZYDIS_DECORATOR_EH:
739 #if !defined(ZYDIS_DISABLE_KNC)
740         if (context->instruction->avx.has_eviction_hint)
741         {
742             ZYDIS_BUFFER_APPEND_CASE(buffer, DECO_EH, formatter->case_decorators);
743         }
744 #endif
745         break;
746     default:
747         return ZYAN_STATUS_INVALID_ARGUMENT;
748     }
749 
750     return ZYAN_STATUS_SUCCESS;
751 }
752 
753 /* ---------------------------------------------------------------------------------------------- */
754 
755 /* ============================================================================================== */
756