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