xref: /haiku/src/libs/zydis/Zydis/Formatter.c (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
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 <Zycore/LibC.h>
28 #include <Zydis/Formatter.h>
29 #include <Zydis/Internal/FormatterATT.h>
30 #include <Zydis/Internal/FormatterIntel.h>
31 #include <Zydis/Internal/String.h>
32 
33 /* ============================================================================================== */
34 /* Constants                                                                                      */
35 /* ============================================================================================== */
36 
37 /* ---------------------------------------------------------------------------------------------- */
38 /* Formatter presets                                                                              */
39 /* ---------------------------------------------------------------------------------------------- */
40 
41 static const ZydisFormatter* const FORMATTER_PRESETS[ZYDIS_FORMATTER_STYLE_MAX_VALUE + 1] =
42 {
43     &FORMATTER_ATT,
44     &FORMATTER_INTEL,
45     &FORMATTER_INTEL_MASM
46 };
47 
48 /* ---------------------------------------------------------------------------------------------- */
49 
50 /* ============================================================================================== */
51 /* Internal functions                                                                             */
52 /* ============================================================================================== */
53 
54 /* ---------------------------------------------------------------------------------------------- */
55 /* Helper functions                                                                               */
56 /* ---------------------------------------------------------------------------------------------- */
57 
58 static void ZydisFormatterBufferInit(ZydisFormatterBuffer* buffer, char* user_buffer,
59     ZyanUSize length)
60 {
61     ZYAN_ASSERT(buffer);
62     ZYAN_ASSERT(user_buffer);
63     ZYAN_ASSERT(length);
64 
65     buffer->is_token_list                   = ZYAN_FALSE;
66     buffer->capacity                        = 0;
67     buffer->string.flags                    = ZYAN_STRING_HAS_FIXED_CAPACITY;
68     buffer->string.vector.allocator         = ZYAN_NULL;
69     buffer->string.vector.growth_factor     = 1;
70     buffer->string.vector.shrink_threshold  = 0;
71     buffer->string.vector.destructor        = ZYAN_NULL;
72     buffer->string.vector.element_size      = sizeof(char);
73     buffer->string.vector.size              = 1;
74     buffer->string.vector.capacity          = length;
75     buffer->string.vector.data              = user_buffer;
76 
77     *user_buffer = '\0';
78 }
79 
80 static void ZydisFormatterBufferInitTokenized(ZydisFormatterBuffer* buffer,
81     ZydisFormatterToken** first_token, void* user_buffer, ZyanUSize length)
82 {
83     ZYAN_ASSERT(buffer);
84     ZYAN_ASSERT(first_token);
85     ZYAN_ASSERT(user_buffer);
86     ZYAN_ASSERT(length);
87 
88     *first_token = user_buffer;
89     (*first_token)->type = ZYDIS_TOKEN_INVALID;
90     (*first_token)->next = 0;
91 
92     user_buffer = (ZyanU8*)user_buffer + sizeof(ZydisFormatterToken);
93     length -= sizeof(ZydisFormatterToken);
94 
95     buffer->is_token_list                  = ZYAN_TRUE;
96     buffer->capacity                       = length;
97     buffer->string.flags                   = ZYAN_STRING_HAS_FIXED_CAPACITY;
98     buffer->string.vector.allocator        = ZYAN_NULL;
99     buffer->string.vector.growth_factor    = 1;
100     buffer->string.vector.shrink_threshold = 0;
101     buffer->string.vector.destructor       = ZYAN_NULL;
102     buffer->string.vector.element_size     = sizeof(char);
103     buffer->string.vector.size             = 1;
104     buffer->string.vector.capacity         = length;
105     buffer->string.vector.data             = user_buffer;
106 
107     *(char*)user_buffer = '\0';
108 }
109 
110 /* ---------------------------------------------------------------------------------------------- */
111 
112 /* ============================================================================================== */
113 /* Exported functions                                                                             */
114 /* ============================================================================================== */
115 
116 /* ---------------------------------------------------------------------------------------------- */
117 /* Initialization                                                                                 */
118 /* ---------------------------------------------------------------------------------------------- */
119 
120 ZyanStatus ZydisFormatterInit(ZydisFormatter* formatter, ZydisFormatterStyle style)
121 {
122     if (!formatter || ((ZyanUSize)style > ZYDIS_FORMATTER_STYLE_MAX_VALUE))
123     {
124         return ZYAN_STATUS_INVALID_ARGUMENT;
125     }
126 
127     ZYAN_MEMCPY(formatter, FORMATTER_PRESETS[style], sizeof(*formatter));
128 
129     return ZYAN_STATUS_SUCCESS;
130 }
131 
132 /* ---------------------------------------------------------------------------------------------- */
133 /* Setter                                                                                         */
134 /* ---------------------------------------------------------------------------------------------- */
135 
136 ZyanStatus ZydisFormatterSetProperty(ZydisFormatter* formatter, ZydisFormatterProperty property,
137     ZyanUPointer value)
138 {
139     if (!formatter)
140     {
141         return ZYAN_STATUS_INVALID_ARGUMENT;
142     }
143 
144     ZydisNumericBase base = (ZydisNumericBase)(-1);
145     ZyanU8 index = 0xFF;
146 
147     switch (property)
148     {
149     case ZYDIS_FORMATTER_PROP_FORCE_SIZE:
150     {
151         formatter->force_memory_size = (value) ? ZYAN_TRUE : ZYAN_FALSE;
152         break;
153     }
154     case ZYDIS_FORMATTER_PROP_FORCE_SEGMENT:
155     {
156         formatter->force_memory_segment = (value) ? ZYAN_TRUE : ZYAN_FALSE;
157         break;
158     }
159     case ZYDIS_FORMATTER_PROP_FORCE_SCALE_ONE:
160     {
161         formatter->force_memory_scale = (value) ? ZYAN_TRUE : ZYAN_FALSE;
162         break;
163     }
164     case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_BRANCHES:
165     {
166         formatter->force_relative_branches = (value) ? ZYAN_TRUE : ZYAN_FALSE;
167         break;
168     }
169     case ZYDIS_FORMATTER_PROP_FORCE_RELATIVE_RIPREL:
170     {
171         formatter->force_relative_riprel = (value) ? ZYAN_TRUE : ZYAN_FALSE;
172         break;
173     }
174     case ZYDIS_FORMATTER_PROP_PRINT_BRANCH_SIZE:
175     {
176         formatter->print_branch_size = (value) ? ZYAN_TRUE : ZYAN_FALSE;
177         break;
178     }
179     case ZYDIS_FORMATTER_PROP_DETAILED_PREFIXES:
180     {
181         formatter->detailed_prefixes = (value) ? ZYAN_TRUE : ZYAN_FALSE;
182         break;
183     }
184     case ZYDIS_FORMATTER_PROP_ADDR_BASE:
185     {
186         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
187         {
188             return ZYAN_STATUS_INVALID_ARGUMENT;
189         }
190         formatter->addr_base = (ZydisNumericBase)value;
191         break;
192     }
193     case ZYDIS_FORMATTER_PROP_ADDR_SIGNEDNESS:
194     {
195         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
196         {
197             return ZYAN_STATUS_INVALID_ARGUMENT;
198         }
199         formatter->addr_signedness = (ZydisSignedness)value;
200         break;
201     }
202     case ZYDIS_FORMATTER_PROP_ADDR_PADDING_ABSOLUTE:
203     {
204         if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) &&
205             (value > 0xFF))
206         {
207             return ZYAN_STATUS_INVALID_ARGUMENT;
208         }
209         formatter->addr_padding_absolute = (ZydisPadding)value;
210         break;
211     }
212     case ZYDIS_FORMATTER_PROP_ADDR_PADDING_RELATIVE:
213     {
214         if (((ZydisPadding)value != ZYDIS_PADDING_AUTO) &&
215             (value > 0xFF))
216         {
217             return ZYAN_STATUS_INVALID_ARGUMENT;
218         }
219         formatter->addr_padding_relative = (ZydisPadding)value;
220         break;
221     }
222     case ZYDIS_FORMATTER_PROP_DISP_BASE:
223     {
224         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
225         {
226             return ZYAN_STATUS_INVALID_ARGUMENT;
227         }
228         formatter->disp_base = (ZydisNumericBase)value;
229         break;
230     }
231     case ZYDIS_FORMATTER_PROP_DISP_SIGNEDNESS:
232     {
233         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
234         {
235             return ZYAN_STATUS_INVALID_ARGUMENT;
236         }
237         formatter->disp_signedness = (ZydisSignedness)value;
238         break;
239     }
240     case ZYDIS_FORMATTER_PROP_DISP_PADDING:
241     {
242         if ((ZydisPadding)value == ZYDIS_PADDING_AUTO)
243         {
244             if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE)
245             {
246                 return ZYAN_STATUS_INVALID_ARGUMENT;
247             }
248             formatter->disp_padding = FORMATTER_PRESETS[formatter->style]->disp_padding;
249         }
250         else if (value > 0xFF)
251         {
252             return ZYAN_STATUS_INVALID_ARGUMENT;
253         }
254         formatter->disp_padding = (ZydisPadding)value;
255         break;
256     }
257     case ZYDIS_FORMATTER_PROP_IMM_BASE:
258     {
259         if (value > ZYDIS_NUMERIC_BASE_MAX_VALUE)
260         {
261             return ZYAN_STATUS_INVALID_ARGUMENT;
262         }
263         formatter->imm_base = (ZydisNumericBase)value;
264         break;
265     }
266     case ZYDIS_FORMATTER_PROP_IMM_SIGNEDNESS:
267     {
268         if (value > ZYDIS_SIGNEDNESS_MAX_VALUE)
269         {
270             return ZYAN_STATUS_INVALID_ARGUMENT;
271         }
272         formatter->imm_signedness  = (ZydisSignedness)value;
273         break;
274     }
275     case ZYDIS_FORMATTER_PROP_IMM_PADDING:
276     {
277         if ((ZydisPadding)value == ZYDIS_PADDING_AUTO)
278         {
279             if ((ZyanUSize)formatter->style > ZYDIS_FORMATTER_STYLE_MAX_VALUE)
280             {
281                 return ZYAN_STATUS_INVALID_ARGUMENT;
282             }
283             formatter->imm_padding = FORMATTER_PRESETS[formatter->style]->imm_padding;
284         }
285         else if (value > 0xFF)
286         {
287             return ZYAN_STATUS_INVALID_ARGUMENT;
288         }
289         formatter->imm_padding = (ZydisPadding)value;
290         break;
291     }
292     case ZYDIS_FORMATTER_PROP_UPPERCASE_PREFIXES:
293     {
294         formatter->case_prefixes = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
295         break;
296     }
297     case ZYDIS_FORMATTER_PROP_UPPERCASE_MNEMONIC:
298     {
299         formatter->case_mnemonic = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
300         break;
301     }
302     case ZYDIS_FORMATTER_PROP_UPPERCASE_REGISTERS:
303     {
304         formatter->case_registers = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
305         break;
306     }
307     case ZYDIS_FORMATTER_PROP_UPPERCASE_TYPECASTS:
308     {
309         formatter->case_typecasts = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
310         break;
311     }
312     case ZYDIS_FORMATTER_PROP_UPPERCASE_DECORATORS:
313     {
314         formatter->case_decorators = (value) ? ZYDIS_LETTER_CASE_UPPER : ZYDIS_LETTER_CASE_DEFAULT;
315         break;
316     }
317     case ZYDIS_FORMATTER_PROP_DEC_PREFIX:
318     {
319         base  = ZYDIS_NUMERIC_BASE_DEC;
320         index = 0;
321         break;
322     }
323     case ZYDIS_FORMATTER_PROP_DEC_SUFFIX:
324     {
325         base  = ZYDIS_NUMERIC_BASE_DEC;
326         index = 1;
327         break;
328     }
329     case ZYDIS_FORMATTER_PROP_HEX_UPPERCASE:
330     {
331         formatter->hex_uppercase = (value) ? ZYAN_TRUE : ZYAN_FALSE;
332         break;
333     }
334     case ZYDIS_FORMATTER_PROP_HEX_FORCE_LEADING_NUMBER:
335     {
336         formatter->hex_force_leading_number = (value) ? ZYAN_TRUE : ZYAN_FALSE;
337         break;
338     }
339     case ZYDIS_FORMATTER_PROP_HEX_PREFIX:
340     {
341         base  = ZYDIS_NUMERIC_BASE_HEX;
342         index = 0;
343         break;
344     }
345     case ZYDIS_FORMATTER_PROP_HEX_SUFFIX:
346     {
347         base  = ZYDIS_NUMERIC_BASE_HEX;
348         index = 1;
349         break;
350     }
351     default:
352         return ZYAN_STATUS_INVALID_ARGUMENT;
353     }
354 
355     // Set prefix or suffix
356     if (base != (ZydisNumericBase)(-1))
357     {
358         if (value)
359         {
360             const ZyanUSize len = ZYAN_STRLEN((char*)value);
361             if (len > 10)
362             {
363                 return ZYAN_STATUS_INVALID_ARGUMENT;
364             }
365             ZYAN_MEMCPY(formatter->number_format[base][index].buffer, (void*)value, len);
366             formatter->number_format[base][index].buffer[len] = '\0';
367             formatter->number_format[base][index].string_data.string.vector.data =
368                 formatter->number_format[base][index].buffer;
369             formatter->number_format[base][index].string_data.string.vector.size = len + 1;
370             formatter->number_format[base][index].string =
371                 &formatter->number_format[base][index].string_data;
372         } else
373         {
374             formatter->number_format[base][index].string = ZYAN_NULL;
375         }
376     }
377 
378     return ZYAN_STATUS_SUCCESS;
379 }
380 
381 ZyanStatus ZydisFormatterSetHook(ZydisFormatter* formatter, ZydisFormatterFunction type,
382     const void** callback)
383 {
384     if (!formatter || !callback || ((ZyanUSize)type > ZYDIS_FORMATTER_FUNC_MAX_VALUE))
385     {
386         return ZYAN_STATUS_INVALID_ARGUMENT;
387     }
388 
389     const void* const temp = *callback;
390 
391     // The following code relies on the order of the enum values and the function fields inside
392     // the `ZydisFormatter` struct
393 
394 #ifdef ZYAN_DEBUG
395     const ZyanUPointer* test = (ZyanUPointer*)(&formatter->func_pre_instruction + type);
396     switch (type)
397     {
398     case ZYDIS_FORMATTER_FUNC_PRE_INSTRUCTION:
399         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_instruction   ); break;
400     case ZYDIS_FORMATTER_FUNC_POST_INSTRUCTION:
401         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_instruction  ); break;
402     case ZYDIS_FORMATTER_FUNC_FORMAT_INSTRUCTION:
403         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_instruction); break;
404     case ZYDIS_FORMATTER_FUNC_PRE_OPERAND:
405         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_pre_operand       ); break;
406     case ZYDIS_FORMATTER_FUNC_POST_OPERAND:
407         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_post_operand      ); break;
408     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_REG:
409         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_reg); break;
410     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_MEM:
411         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_mem); break;
412     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_PTR:
413         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_ptr); break;
414     case ZYDIS_FORMATTER_FUNC_FORMAT_OPERAND_IMM:
415         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_format_operand_imm); break;
416     case ZYDIS_FORMATTER_FUNC_PRINT_MNEMONIC:
417         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_mnemonic    ); break;
418     case ZYDIS_FORMATTER_FUNC_PRINT_REGISTER:
419         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_register    ); break;
420     case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_ABS:
421         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_abs ); break;
422     case ZYDIS_FORMATTER_FUNC_PRINT_ADDRESS_REL:
423         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_address_rel ); break;
424     case ZYDIS_FORMATTER_FUNC_PRINT_DISP:
425         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_disp        ); break;
426     case ZYDIS_FORMATTER_FUNC_PRINT_IMM:
427         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_imm         ); break;
428     case ZYDIS_FORMATTER_FUNC_PRINT_TYPECAST:
429         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_typecast    ); break;
430     case ZYDIS_FORMATTER_FUNC_PRINT_SEGMENT:
431         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_segment     ); break;
432     case ZYDIS_FORMATTER_FUNC_PRINT_PREFIXES:
433         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_prefixes    ); break;
434     case ZYDIS_FORMATTER_FUNC_PRINT_DECORATOR:
435         ZYAN_ASSERT(test == (ZyanUPointer*)&formatter->func_print_decorator   ); break;
436     default:
437         ZYAN_UNREACHABLE;
438     }
439 #endif
440 
441     *callback = *(const void**)(&formatter->func_pre_instruction + type);
442     if (!temp)
443     {
444         return ZYAN_STATUS_SUCCESS;
445     }
446     ZYAN_MEMCPY(&formatter->func_pre_instruction + type, &temp, sizeof(ZyanUPointer));
447 
448     return ZYAN_STATUS_SUCCESS;
449 }
450 
451 /* ---------------------------------------------------------------------------------------------- */
452 /* Formatting                                                                                     */
453 /* ---------------------------------------------------------------------------------------------- */
454 
455 ZyanStatus ZydisFormatterFormatInstruction(const ZydisFormatter* formatter,
456     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
457     ZyanU8 operand_count, char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
458 {
459     if (!formatter || !instruction || (operand_count && !operands) ||
460         (operand_count > ZYDIS_MAX_OPERAND_COUNT) ||
461         (operand_count < instruction->operand_count_visible) || !buffer || (length == 0))
462     {
463         return ZYAN_STATUS_INVALID_ARGUMENT;
464     }
465 
466     ZydisFormatterBuffer formatter_buffer;
467     ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
468 
469     ZydisFormatterContext context;
470     context.instruction     = instruction;
471     context.operands        = operands;
472     context.runtime_address = runtime_address;
473     context.operand         = ZYAN_NULL;
474     context.user_data       = user_data;
475 
476     if (formatter->func_pre_instruction)
477     {
478         ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
479     }
480 
481     ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
482 
483     if (formatter->func_post_instruction)
484     {
485         ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
486     }
487 
488     return ZYAN_STATUS_SUCCESS;
489 }
490 
491 ZyanStatus ZydisFormatterFormatOperand(const ZydisFormatter* formatter,
492     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
493     char* buffer, ZyanUSize length, ZyanU64 runtime_address, void* user_data)
494 {
495     if (!formatter || !instruction || !operand || !buffer || (length == 0))
496     {
497         return ZYAN_STATUS_INVALID_ARGUMENT;
498     }
499 
500     ZydisFormatterBuffer formatter_buffer;
501     ZydisFormatterBufferInit(&formatter_buffer, buffer, length);
502 
503     ZydisFormatterContext context;
504     context.instruction     = instruction;
505     context.operands        = ZYAN_NULL;
506     context.runtime_address = runtime_address;
507     context.operand         = operand;
508     context.user_data       = user_data;
509 
510     // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
511     // to skip the only operand printed by this function
512 
513     if (formatter->func_pre_operand)
514     {
515         ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
516     }
517 
518     switch (context.operand->type)
519     {
520     case ZYDIS_OPERAND_TYPE_REGISTER:
521         ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
522         break;
523     case ZYDIS_OPERAND_TYPE_MEMORY:
524         ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
525         break;
526     case ZYDIS_OPERAND_TYPE_IMMEDIATE:
527         ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
528         break;
529     case ZYDIS_OPERAND_TYPE_POINTER:
530         ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
531         break;
532     default:
533         return ZYAN_STATUS_INVALID_ARGUMENT;
534     }
535 
536     if (formatter->func_post_operand)
537     {
538         ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
539     }
540 
541     return ZYAN_STATUS_SUCCESS;
542 }
543 
544 /* ---------------------------------------------------------------------------------------------- */
545 /* Tokenizing                                                                                     */
546 /* ---------------------------------------------------------------------------------------------- */
547 
548 ZyanStatus ZydisFormatterTokenizeInstruction(const ZydisFormatter* formatter,
549     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operands,
550     ZyanU8 operand_count, void* buffer, ZyanUSize length, ZyanU64 runtime_address,
551     ZydisFormatterTokenConst** token, void* user_data)
552 {
553     if (!formatter || !instruction || (operand_count && !operands) ||
554         (operand_count > ZYDIS_MAX_OPERAND_COUNT) ||
555         (operand_count < instruction->operand_count_visible) || !buffer ||
556         (length <= sizeof(ZydisFormatterToken)) || !token)
557     {
558         return ZYAN_STATUS_INVALID_ARGUMENT;
559     }
560 
561     ZydisFormatterBuffer formatter_buffer;
562     ZydisFormatterToken* first_token;
563     ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
564 
565     ZydisFormatterContext context;
566     context.instruction     = instruction;
567     context.operands        = operands;
568     context.runtime_address = runtime_address;
569     context.operand         = ZYAN_NULL;
570     context.user_data       = user_data;
571 
572     if (formatter->func_pre_instruction)
573     {
574         ZYAN_CHECK(formatter->func_pre_instruction(formatter, &formatter_buffer, &context));
575     }
576 
577     ZYAN_CHECK(formatter->func_format_instruction(formatter, &formatter_buffer, &context));
578 
579     if (formatter->func_post_instruction)
580     {
581         ZYAN_CHECK(formatter->func_post_instruction(formatter, &formatter_buffer, &context));
582     }
583 
584     if (first_token->next)
585     {
586         *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
587             first_token->next);
588         return ZYAN_STATUS_SUCCESS;
589     }
590 
591     *token = first_token;
592     return ZYAN_STATUS_SUCCESS;
593 }
594 
595 ZyanStatus ZydisFormatterTokenizeOperand(const ZydisFormatter* formatter,
596     const ZydisDecodedInstruction* instruction, const ZydisDecodedOperand* operand,
597     void* buffer, ZyanUSize length, ZyanU64 runtime_address, ZydisFormatterTokenConst** token,
598     void* user_data)
599 {
600     if (!formatter || !instruction || !operand || !buffer ||
601         (length <= sizeof(ZydisFormatterToken)) || !token)
602     {
603         return ZYAN_STATUS_INVALID_ARGUMENT;
604     }
605 
606     ZydisFormatterToken* first_token;
607     ZydisFormatterBuffer formatter_buffer;
608     ZydisFormatterBufferInitTokenized(&formatter_buffer, &first_token, buffer, length);
609 
610     ZydisFormatterContext context;
611     context.instruction     = instruction;
612     context.operands        = ZYAN_NULL;
613     context.runtime_address = runtime_address;
614     context.operand         = operand;
615     context.user_data       = user_data;
616 
617     // We ignore `ZYDIS_STATUS_SKIP_TOKEN` for all operand-functions as it does not make any sense
618     // to skip the only operand printed by this function
619 
620     if (formatter->func_pre_operand)
621     {
622         ZYAN_CHECK(formatter->func_pre_operand(formatter, &formatter_buffer, &context));
623     }
624 
625     switch (context.operand->type)
626     {
627     case ZYDIS_OPERAND_TYPE_REGISTER:
628         ZYAN_CHECK(formatter->func_format_operand_reg(formatter, &formatter_buffer, &context));
629         break;
630     case ZYDIS_OPERAND_TYPE_MEMORY:
631         ZYAN_CHECK(formatter->func_format_operand_mem(formatter, &formatter_buffer, &context));
632         break;
633     case ZYDIS_OPERAND_TYPE_IMMEDIATE:
634         ZYAN_CHECK(formatter->func_format_operand_imm(formatter, &formatter_buffer, &context));
635         break;
636     case ZYDIS_OPERAND_TYPE_POINTER:
637         ZYAN_CHECK(formatter->func_format_operand_ptr(formatter, &formatter_buffer, &context));
638         break;
639     default:
640         return ZYAN_STATUS_INVALID_ARGUMENT;
641     }
642 
643     if (formatter->func_post_operand)
644     {
645         ZYAN_CHECK(formatter->func_post_operand(formatter, &formatter_buffer, &context));
646     }
647 
648     if (first_token->next)
649     {
650         *token = (ZydisFormatterTokenConst*)((ZyanU8*)first_token + sizeof(ZydisFormatterToken) +
651             first_token->next);
652         return ZYAN_STATUS_SUCCESS;
653     }
654 
655     *token = first_token;
656     return ZYAN_STATUS_SUCCESS;
657 }
658 
659 /* ============================================================================================== */
660 
661 /* ============================================================================================== */
662