xref: /haiku/src/libs/zydis/Zydis/FormatterIntel.c (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
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/FormatterIntel.h>
28 #include <Zydis/Utils.h>
29 #include <Zycore/Format.h>
30 
31 /* ============================================================================================== */
32 /* Constants                                                                                      */
33 /* ============================================================================================== */
34 
35 #include <Generated/FormatterStrings.inc>
36 
37 /* ============================================================================================== */
38 /* Formatter functions                                                                            */
39 /* ============================================================================================== */
40 
41 /* ---------------------------------------------------------------------------------------------- */
42 /* Intel                                                                                          */
43 /* ---------------------------------------------------------------------------------------------- */
44 
45 ZyanStatus ZydisFormatterIntelFormatInstruction(const ZydisFormatter* formatter,
46     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
47 {
48     ZYAN_ASSERT(formatter);
49     ZYAN_ASSERT(buffer);
50     ZYAN_ASSERT(context);
51     ZYAN_ASSERT(context->instruction);
52     ZYAN_ASSERT(context->operands);
53 
54     ZYAN_CHECK(formatter->func_print_prefixes(formatter, buffer, context));
55     ZYAN_CHECK(formatter->func_print_mnemonic(formatter, buffer, context));
56 
57     ZyanUPointer state_mnemonic;
58     ZYDIS_BUFFER_REMEMBER(buffer, state_mnemonic);
59     for (ZyanU8 i = 0; i < context->instruction->operand_count_visible; ++i)
60     {
61         const ZydisDecodedOperand* const operand = &context->operands[i];
62 
63         // Print embedded-mask registers as decorator instead of a regular operand
64         if ((i == 1) && (operand->type == ZYDIS_OPERAND_TYPE_REGISTER) &&
65             (operand->encoding == ZYDIS_OPERAND_ENCODING_MASK))
66         {
67             continue;
68         }
69 
70         ZyanUPointer buffer_state;
71         ZYDIS_BUFFER_REMEMBER(buffer, buffer_state);
72 
73         if (buffer_state != state_mnemonic)
74         {
75             ZYDIS_BUFFER_APPEND(buffer, DELIM_OPERAND);
76         } else
77         {
78             ZYDIS_BUFFER_APPEND(buffer, DELIM_MNEMONIC);
79         }
80 
81         // Set current operand
82         context->operand = operand;
83 
84         ZyanStatus status;
85         if (formatter->func_pre_operand)
86         {
87             status = formatter->func_pre_operand(formatter, buffer, context);
88             if (status == ZYDIS_STATUS_SKIP_TOKEN)
89             {
90                 ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
91                 continue;
92             }
93             if (!ZYAN_SUCCESS(status))
94             {
95                 return status;
96             }
97         }
98 
99         switch (operand->type)
100         {
101         case ZYDIS_OPERAND_TYPE_REGISTER:
102             status = formatter->func_format_operand_reg(formatter, buffer, context);
103             break;
104         case ZYDIS_OPERAND_TYPE_MEMORY:
105             status = formatter->func_format_operand_mem(formatter, buffer, context);
106             break;
107         case ZYDIS_OPERAND_TYPE_POINTER:
108             status = formatter->func_format_operand_ptr(formatter, buffer, context);
109             break;
110         case ZYDIS_OPERAND_TYPE_IMMEDIATE:
111             status = formatter->func_format_operand_imm(formatter, buffer, context);
112             break;
113         default:
114             return ZYAN_STATUS_INVALID_ARGUMENT;
115         }
116         if (status == ZYDIS_STATUS_SKIP_TOKEN)
117         {
118             ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
119             continue;
120         }
121         if (!ZYAN_SUCCESS(status))
122         {
123             return status;
124         }
125 
126         if (formatter->func_post_operand)
127         {
128             status = formatter->func_post_operand(formatter, buffer, context);
129             if (status == ZYDIS_STATUS_SKIP_TOKEN)
130             {
131                 ZYAN_CHECK(ZydisFormatterBufferRestore(buffer, buffer_state));
132                 continue;
133             }
134             if (ZYAN_SUCCESS(status))
135             {
136                 return status;
137             }
138         }
139 
140 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
141         if ((context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
142             (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
143         {
144             if  ((i == 0) &&
145                  (context->instruction->operand_count_visible > 1) &&
146                  (context->operands[i + 1].encoding == ZYDIS_OPERAND_ENCODING_MASK))
147             {
148                 ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
149                     ZYDIS_DECORATOR_MASK));
150             }
151             if (operand->type == ZYDIS_OPERAND_TYPE_MEMORY)
152             {
153                 ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
154                     ZYDIS_DECORATOR_BC));
155                 if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
156                 {
157                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
158                         ZYDIS_DECORATOR_CONVERSION));
159                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
160                         ZYDIS_DECORATOR_EH));
161                 }
162             } else
163             {
164                 ZyanBool decorate_operand;
165                 if (i == (context->instruction->operand_count_visible - 1))
166                 {
167                     decorate_operand = operand->type != ZYDIS_OPERAND_TYPE_IMMEDIATE;
168                 }
169                 else
170                 {
171                     decorate_operand =
172                         (context->instruction->operand_count_visible > (i + 1)) &&
173                         ((context->operands[i + 1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) ||
174                         (context->operands[i + 1].visibility == ZYDIS_OPERAND_VISIBILITY_HIDDEN));
175                 }
176                 if (decorate_operand)
177                 {
178                     if (context->instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)
179                     {
180                         ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
181                             ZYDIS_DECORATOR_SWIZZLE));
182                     }
183                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
184                         ZYDIS_DECORATOR_RC));
185                     ZYAN_CHECK(formatter->func_print_decorator(formatter, buffer, context,
186                         ZYDIS_DECORATOR_SAE));
187                 }
188             }
189         }
190 #endif
191     }
192 
193     return ZYAN_STATUS_SUCCESS;
194 }
195 
196 ZyanStatus ZydisFormatterIntelFormatOperandMEM(const ZydisFormatter* formatter,
197     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
198 {
199     ZYAN_ASSERT(formatter);
200     ZYAN_ASSERT(buffer);
201     ZYAN_ASSERT(context);
202 
203     if ((context->operand->mem.type == ZYDIS_MEMOP_TYPE_MEM) ||
204         (context->operand->mem.type == ZYDIS_MEMOP_TYPE_AGEN) ||
205         (context->operand->mem.type == ZYDIS_MEMOP_TYPE_VSIB))
206     {
207         ZYAN_CHECK(formatter->func_print_typecast(formatter, buffer, context));
208     }
209     ZYAN_CHECK(formatter->func_print_segment(formatter, buffer, context));
210 
211     ZYDIS_BUFFER_APPEND(buffer, MEMORY_BEGIN_INTEL);
212 
213     const ZyanBool absolute = !formatter->force_relative_riprel &&
214         (context->runtime_address != ZYDIS_RUNTIME_ADDRESS_NONE);
215     if (absolute && context->operand->mem.disp.has_displacement &&
216         (context->operand->mem.index == ZYDIS_REGISTER_NONE) &&
217        ((context->operand->mem.base  == ZYDIS_REGISTER_NONE) ||
218         (context->operand->mem.base  == ZYDIS_REGISTER_EIP ) ||
219         (context->operand->mem.base  == ZYDIS_REGISTER_RIP )))
220     {
221         // EIP/RIP-relative or absolute-displacement address operand
222         ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
223     } else
224     {
225         const ZyanBool should_print_reg = context->operand->mem.base != ZYDIS_REGISTER_NONE;
226         const ZyanBool should_print_idx = context->operand->mem.index != ZYDIS_REGISTER_NONE;
227         const ZyanBool neither_reg_nor_idx = !should_print_reg && !should_print_idx;
228 
229         // Regular memory operand
230         if (should_print_reg)
231         {
232             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
233                 context->operand->mem.base));
234         }
235         if (should_print_idx)
236         {
237             if (context->operand->mem.base != ZYDIS_REGISTER_NONE)
238             {
239                 ZYDIS_BUFFER_APPEND(buffer, ADD);
240             }
241             ZYAN_CHECK(formatter->func_print_register(formatter, buffer, context,
242                 context->operand->mem.index));
243             if (context->operand->mem.scale &&
244                 (context->operand->mem.type != ZYDIS_MEMOP_TYPE_MIB) &&
245                 ((context->operand->mem.scale > 1) || formatter->force_memory_scale))
246             {
247                 ZYDIS_BUFFER_APPEND(buffer, MUL);
248                 ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_IMMEDIATE);
249                 ZYAN_CHECK(ZydisStringAppendDecU(&buffer->string, context->operand->mem.scale, 0,
250                     ZYAN_NULL, ZYAN_NULL));
251             }
252         }
253         if (neither_reg_nor_idx)
254         {
255             ZYAN_CHECK(formatter->func_print_address_abs(formatter, buffer, context));
256         } else if (context->operand->mem.disp.has_displacement && context->operand->mem.disp.value)
257         {
258             ZYAN_CHECK(formatter->func_print_disp(formatter, buffer, context));
259         }
260     }
261 
262     ZYDIS_BUFFER_APPEND(buffer, MEMORY_END_INTEL);
263     return ZYAN_STATUS_SUCCESS;
264 }
265 
266 ZyanStatus ZydisFormatterIntelPrintMnemonic(const ZydisFormatter* formatter,
267     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
268 {
269     ZYAN_ASSERT(formatter);
270     ZYAN_ASSERT(buffer);
271     ZYAN_ASSERT(context);
272 
273     const ZydisShortString* mnemonic = ZydisMnemonicGetStringWrapped(
274         context->instruction->mnemonic);
275     if (!mnemonic)
276     {
277         ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_MNEMONIC, formatter->case_mnemonic);
278         return ZYAN_STATUS_SUCCESS;
279     }
280 
281     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_MNEMONIC);
282     ZYAN_CHECK(ZydisStringAppendShortCase(&buffer->string, mnemonic, formatter->case_mnemonic));
283     if (context->instruction->meta.branch_type == ZYDIS_BRANCH_TYPE_FAR)
284     {
285         return ZydisStringAppendShortCase(&buffer->string, &STR_FAR, formatter->case_mnemonic);
286     }
287     if (formatter->print_branch_size)
288     {
289         switch (context->instruction->meta.branch_type)
290         {
291         case ZYDIS_BRANCH_TYPE_NONE:
292             break;
293         case ZYDIS_BRANCH_TYPE_SHORT:
294             return ZydisStringAppendShortCase(&buffer->string, &STR_SHORT,
295                 formatter->case_mnemonic);
296         case ZYDIS_BRANCH_TYPE_NEAR:
297             return ZydisStringAppendShortCase(&buffer->string, &STR_NEAR,
298                 formatter->case_mnemonic);
299         default:
300             return ZYAN_STATUS_INVALID_ARGUMENT;
301         }
302     }
303 
304     return ZYAN_STATUS_SUCCESS;
305 }
306 
307 ZyanStatus ZydisFormatterIntelPrintRegister(const ZydisFormatter* formatter,
308     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context, ZydisRegister reg)
309 {
310     ZYAN_UNUSED(context);
311 
312     ZYAN_ASSERT(formatter);
313     ZYAN_ASSERT(buffer);
314     ZYAN_ASSERT(context);
315 
316     const ZydisShortString* str = ZydisRegisterGetStringWrapped(reg);
317     if (!str)
318     {
319         ZYDIS_BUFFER_APPEND_CASE(buffer, INVALID_REG, formatter->case_registers);
320         return ZYAN_STATUS_SUCCESS;
321     }
322 
323     ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_REGISTER);
324     return ZydisStringAppendShortCase(&buffer->string, str, formatter->case_registers);
325 }
326 
327 ZyanStatus ZydisFormatterIntelPrintDISP(const ZydisFormatter* formatter,
328     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
329 {
330     ZYAN_ASSERT(formatter);
331     ZYAN_ASSERT(buffer);
332     ZYAN_ASSERT(context);
333 
334     switch (formatter->disp_signedness)
335     {
336     case ZYDIS_SIGNEDNESS_AUTO:
337     case ZYDIS_SIGNEDNESS_SIGNED:
338         if (context->operand->mem.disp.value < 0)
339         {
340             if ((context->operand->mem.base  != ZYDIS_REGISTER_NONE) ||
341                 (context->operand->mem.index != ZYDIS_REGISTER_NONE))
342             {
343                 ZYDIS_BUFFER_APPEND(buffer, SUB);
344             }
345             ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
346             ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
347                 ZyanAbsI64(context->operand->mem.disp.value), formatter->disp_padding,
348                 formatter->hex_force_leading_number);
349             break;
350         }
351         ZYAN_FALLTHROUGH;
352     case ZYDIS_SIGNEDNESS_UNSIGNED:
353         if ((context->operand->mem.base  != ZYDIS_REGISTER_NONE) ||
354             (context->operand->mem.index != ZYDIS_REGISTER_NONE))
355         {
356             ZYDIS_BUFFER_APPEND(buffer, ADD);
357         }
358         ZYDIS_BUFFER_APPEND_TOKEN(buffer, ZYDIS_TOKEN_DISPLACEMENT);
359         ZYDIS_STRING_APPEND_NUM_U(formatter, formatter->disp_base, &buffer->string,
360             context->operand->mem.disp.value, formatter->disp_padding,
361             formatter->hex_force_leading_number);
362         break;
363     default:
364         return ZYAN_STATUS_INVALID_ARGUMENT;
365     }
366 
367     return ZYAN_STATUS_SUCCESS;
368 }
369 
370 ZyanStatus ZydisFormatterIntelPrintTypecast(const ZydisFormatter* formatter,
371     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
372 {
373     ZYAN_ASSERT(formatter);
374     ZYAN_ASSERT(buffer);
375     ZYAN_ASSERT(context);
376 
377     switch (ZydisFormatterHelperGetExplicitSize(formatter, context, context->operand))
378     {
379     case   8: ZYDIS_BUFFER_APPEND(buffer, SIZE_8_INTEL  ); break;
380     case  16: ZYDIS_BUFFER_APPEND(buffer, SIZE_16_INTEL ); break;
381     case  32: ZYDIS_BUFFER_APPEND(buffer, SIZE_32_INTEL ); break;
382     case  48: ZYDIS_BUFFER_APPEND(buffer, SIZE_48       ); break;
383     case  64: ZYDIS_BUFFER_APPEND(buffer, SIZE_64_INTEL ); break;
384     case  80: ZYDIS_BUFFER_APPEND(buffer, SIZE_80       ); break;
385     case 128: ZYDIS_BUFFER_APPEND(buffer, SIZE_128_INTEL); break;
386     case 256: ZYDIS_BUFFER_APPEND(buffer, SIZE_256_INTEL); break;
387     case 512: ZYDIS_BUFFER_APPEND(buffer, SIZE_512_INTEL); break;
388     default:
389         break;
390     }
391 
392     return ZYAN_STATUS_SUCCESS;
393 }
394 
395 /* ---------------------------------------------------------------------------------------------- */
396 /* MASM                                                                                           */
397 /* ---------------------------------------------------------------------------------------------- */
398 
399 ZyanStatus ZydisFormatterIntelFormatInstructionMASM(const ZydisFormatter* formatter,
400     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
401 {
402     ZYAN_ASSERT(formatter);
403     ZYAN_ASSERT(buffer);
404     ZYAN_ASSERT(context);
405 
406     // Force the formatter to always call our MASM `ZYDIS_FORMATTER_PRINT_ADDRESS_ABS` function.
407     // This implicitly omits printing of the `RIP`/`EIP` registers for `RIP`/`EIP`-relative
408     // memory operands
409     context->runtime_address = 0;
410 
411     return ZydisFormatterIntelFormatInstruction(formatter, buffer, context);
412 }
413 
414 ZyanStatus ZydisFormatterIntelPrintAddressMASM(const ZydisFormatter* formatter,
415     ZydisFormatterBuffer* buffer, ZydisFormatterContext* context)
416 {
417     ZYAN_ASSERT(formatter);
418     ZYAN_ASSERT(buffer);
419     ZYAN_ASSERT(context);
420 
421     ZyanU64 address;
422     ZYAN_CHECK(ZydisCalcAbsoluteAddress(context->instruction, context->operand, 0, &address));
423 
424     ZyanU8 padding = (formatter->addr_padding_relative ==
425         ZYDIS_PADDING_AUTO) ? 0 : (ZyanU8)formatter->addr_padding_relative;
426     if ((formatter->addr_padding_relative == ZYDIS_PADDING_AUTO) &&
427         (formatter->addr_base == ZYDIS_NUMERIC_BASE_HEX))
428     {
429         switch (context->instruction->address_width)
430         {
431         case 16:
432             padding =  4;
433             address = (ZyanU16)address;
434             break;
435         case 32:
436             padding =  8;
437             address = (ZyanU32)address;
438             break;
439         case 64:
440             padding = 16;
441             break;
442         default:
443             return ZYAN_STATUS_INVALID_ARGUMENT;
444         }
445     }
446 
447     ZYDIS_BUFFER_APPEND(buffer, ADDR_RELATIVE);
448     ZYDIS_STRING_APPEND_NUM_S(formatter, formatter->addr_base, &buffer->string, address, padding,
449         formatter->hex_force_leading_number, ZYAN_TRUE);
450 
451     return ZYAN_STATUS_SUCCESS;
452 }
453 
454 /* ---------------------------------------------------------------------------------------------- */
455 
456 /* ============================================================================================== */
457