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