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