xref: /haiku/src/libs/zydis/Zydis/Decoder.c (revision 909af08f4328301fbdef1ffb41f566c3b5bec0c7)
1 /***************************************************************************************************
2 
3   Zyan Disassembler Library (Zydis)
4 
5   Original Author : Florian Bernd
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 // ReSharper disable CppClangTidyClangDiagnosticImplicitFallthrough
28 // ReSharper disable CppClangTidyClangDiagnosticSwitchEnum
29 // ReSharper disable CppClangTidyClangDiagnosticCoveredSwitchDefault
30 
31 // Temporarily disabled due to a LLVM issue:
32 // ReSharper disable CppClangTidyBugproneNarrowingConversions
33 
34 #include <Zycore/LibC.h>
35 #include <Zydis/Decoder.h>
36 #include <Zydis/Status.h>
37 #include <Zydis/Internal/DecoderData.h>
38 #include <Zydis/Internal/SharedData.h>
39 
40 /* ============================================================================================== */
41 /* Internal enums and types                                                                       */
42 /* ============================================================================================== */
43 
44 /* ---------------------------------------------------------------------------------------------- */
45 /* Decoder context                                                                                */
46 /* ---------------------------------------------------------------------------------------------- */
47 
48 /**
49  * Defines the `ZydisDecoderState` struct.
50  */
51 typedef struct ZydisDecoderState_
52 {
53     /**
54      * A pointer to the `ZydisDecoder` instance.
55      */
56     const ZydisDecoder* decoder;
57     /**
58      * A pointer to the `ZydisDecoderContext` struct.
59      */
60     ZydisDecoderContext* context;
61     /**
62      * The input buffer.
63      */
64     const ZyanU8* buffer;
65     /**
66      * The input buffer length.
67      */
68     ZyanUSize buffer_len;
69     /**
70      * Prefix information.
71      */
72     struct
73     {
74         /**
75          * Signals, if the instruction has a `LOCK` prefix (`F0`).
76          *
77          * This prefix originally belongs to group 1, but separating it from the other ones makes
78          * parsing easier for us later.
79          */
80         ZyanBool has_lock;
81         /**
82          * The effective prefix of group 1 (either `F2` or `F3`).
83          */
84         ZyanU8 group1;
85         /**
86          * The effective prefix of group 2 (`2E`, `36`, `3E`, `26`, `64` or `65`).
87          */
88         ZyanU8 group2;
89         /**
90          * The effective segment prefix.
91          */
92         ZyanU8 effective_segment;
93         /**
94          * The prefix that should be treated as the mandatory-prefix, if the
95          * current instruction needs one.
96          *
97          * The last `F3`/`F2` prefix has precedence over previous ones and
98          * `F3`/`F2` in general have precedence over `66`.
99          */
100         ZyanU8 mandatory_candidate;
101         /**
102          * The offset of the effective `LOCK` prefix.
103          */
104         ZyanU8 offset_lock;
105         /**
106          * The offset of the effective prefix in group 1.
107          */
108         ZyanU8 offset_group1;
109         /**
110          * The offset of the effective prefix in group 2.
111          */
112         ZyanU8 offset_group2;
113         /**
114          * The offset of the operand-size override prefix (`66`).
115          *
116          * This is the only prefix in group 3.
117          */
118         ZyanU8 offset_osz_override;
119         /**
120          * The offset of the address-size override prefix (`67`).
121          *
122          * This is the only prefix in group 4.
123          */
124         ZyanU8 offset_asz_override;
125         /**
126          * The offset of the effective segment prefix.
127          */
128         ZyanU8 offset_segment;
129         /**
130          * The offset of the mandatory-candidate prefix.
131          */
132         ZyanU8 offset_mandatory;
133         /**
134          * The offset of a possible `CET` `no-lock` prefix.
135          */
136         ZyanI8 offset_notrack;
137     } prefixes;
138 } ZydisDecoderState;
139 
140 /* ---------------------------------------------------------------------------------------------- */
141 /* Register encoding                                                                              */
142 /* ---------------------------------------------------------------------------------------------- */
143 
144 /**
145  * Defines the `ZydisRegisterEncoding` enum.
146  */
147 typedef enum ZydisRegisterEncoding_
148 {
149     ZYDIS_REG_ENCODING_INVALID,
150     /**
151      * The register-id is encoded as part of the opcode (bits [3..0]).
152      *
153      * Possible extension by:
154      * - `REX.B`
155      */
156     ZYDIS_REG_ENCODING_OPCODE,
157     /**
158      * The register-id is encoded in `modrm.reg`.
159      *
160      * Possible extension by:
161      * - `.R`
162      * - `.R'` (vector only, EVEX/MVEX)
163      */
164     ZYDIS_REG_ENCODING_REG,
165     /**
166      * The register-id is encoded in `.vvvv`.
167      *
168      * Possible extension by:
169      * - `.v'` (vector only, EVEX/MVEX).
170      */
171     ZYDIS_REG_ENCODING_NDSNDD,
172     /**
173      * The register-id is encoded in `modrm.rm`.
174      *
175      * Possible extension by:
176      * - `.B`
177      * - `.X` (vector only, EVEX/MVEX)`
178      */
179     ZYDIS_REG_ENCODING_RM,
180     /**
181      * The register-id is encoded in `modrm.rm` or `sib.base` (if `SIB` is present).
182      *
183      * Possible extension by:
184      * - `.B`
185      */
186     ZYDIS_REG_ENCODING_BASE,
187     /**
188      * The register-id is encoded in `sib.index`.
189      *
190      * Possible extension by:
191      * - `.X`
192      */
193     ZYDIS_REG_ENCODING_INDEX,
194     /**
195      * The register-id is encoded in `sib.index`.
196      *
197      * Possible extension by:
198      * - `.X`
199      * - `.V'` (vector only, EVEX/MVEX)
200      */
201     ZYDIS_REG_ENCODING_VIDX,
202     /**
203      * The register-id is encoded in an additional 8-bit immediate value.
204      *
205      * Bits [7:4] in 64-bit mode with possible extension by bit [3] (vector only), bits [7:5] for
206      * all other modes.
207      */
208     ZYDIS_REG_ENCODING_IS4,
209     /**
210      * The register-id is encoded in `EVEX.aaa/MVEX.kkk`.
211      */
212     ZYDIS_REG_ENCODING_MASK,
213 
214     /**
215      * Maximum value of this enum.
216      */
217     ZYDIS_REG_ENCODING_MAX_VALUE = ZYDIS_REG_ENCODING_MASK,
218     /**
219      * The minimum number of bits required to represent all values of this enum.
220      */
221     ZYDIS_REG_ENCODING_REQUIRED_BITS = ZYAN_BITS_TO_REPRESENT(ZYDIS_REG_ENCODING_MAX_VALUE)
222 } ZydisRegisterEncoding;
223 
224 /* ---------------------------------------------------------------------------------------------- */
225 
226 /* ============================================================================================== */
227 /* Internal functions                                                                             */
228 /* ============================================================================================== */
229 
230 /* ---------------------------------------------------------------------------------------------- */
231 /* Input helper functions                                                                         */
232 /* ---------------------------------------------------------------------------------------------- */
233 
234 /**
235  * Reads one byte from the current read-position of the input data-source.
236  *
237  * @param   state       A pointer to the `ZydisDecoderState` struct.
238  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
239  * @param   value       A pointer to the memory that receives the byte from the input data-source.
240  *
241  * @return  A zyan status code.
242  *
243  * This function may fail, if the `ZYDIS_MAX_INSTRUCTION_LENGTH` limit got exceeded, or no more
244  * data is available.
245  */
246 static ZyanStatus ZydisInputPeek(ZydisDecoderState* state,
247     ZydisDecodedInstruction* instruction, ZyanU8* value)
248 {
249     ZYAN_ASSERT(state);
250     ZYAN_ASSERT(instruction);
251     ZYAN_ASSERT(value);
252 
253     if (instruction->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
254     {
255         return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
256     }
257 
258     if (state->buffer_len > 0)
259     {
260         *value = state->buffer[0];
261         return ZYAN_STATUS_SUCCESS;
262     }
263 
264     return ZYDIS_STATUS_NO_MORE_DATA;
265 }
266 
267 /**
268  * Increases the read-position of the input data-source by one byte.
269  *
270  * @param   state       A pointer to the `ZydisDecoderState` instance
271  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
272  *
273  * This function is supposed to get called ONLY after a successful call of `ZydisInputPeek`.
274  *
275  * This function increases the `length` field of the `ZydisDecodedInstruction` struct by one.
276  */
277 static void ZydisInputSkip(ZydisDecoderState* state, ZydisDecodedInstruction* instruction)
278 {
279     ZYAN_ASSERT(state);
280     ZYAN_ASSERT(instruction);
281     ZYAN_ASSERT(instruction->length < ZYDIS_MAX_INSTRUCTION_LENGTH);
282 
283     ++instruction->length;
284     ++state->buffer;
285     --state->buffer_len;
286 }
287 
288 /**
289  * Reads one byte from the current read-position of the input data-source and increases
290  *          the read-position by one byte afterwards.
291  *
292  * @param   state       A pointer to the `ZydisDecoderState` struct.
293  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
294  * @param   value       A pointer to the memory that receives the byte from the input data-source.
295  *
296  * @return  A zyan status code.
297  *
298  * This function acts like a subsequent call of `ZydisInputPeek` and `ZydisInputSkip`.
299  */
300 static ZyanStatus ZydisInputNext(ZydisDecoderState* state,
301     ZydisDecodedInstruction* instruction, ZyanU8* value)
302 {
303     ZYAN_ASSERT(state);
304     ZYAN_ASSERT(instruction);
305     ZYAN_ASSERT(value);
306 
307     if (instruction->length >= ZYDIS_MAX_INSTRUCTION_LENGTH)
308     {
309         return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
310     }
311 
312     if (state->buffer_len > 0)
313     {
314         *value = state->buffer++[0];
315         ++instruction->length;
316         --state->buffer_len;
317         return ZYAN_STATUS_SUCCESS;
318     }
319 
320     return ZYDIS_STATUS_NO_MORE_DATA;
321 }
322 
323 /**
324  * Reads a variable amount of bytes from the current read-position of the input
325  *          data-source and increases the read-position by specified amount of bytes afterwards.
326  *
327  * @param   state           A pointer to the `ZydisDecoderState` struct.
328  * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
329  * @param   value           A pointer to the memory that receives the byte from the input
330  *                          data-source.
331  * @param   number_of_bytes The number of bytes to read from the input data-source.
332  *
333  * @return  A zyan status code.
334  *
335  * This function acts like a subsequent call of `ZydisInputPeek` and `ZydisInputSkip`.
336  */
337 static ZyanStatus ZydisInputNextBytes(ZydisDecoderState* state,
338     ZydisDecodedInstruction* instruction, ZyanU8* value, ZyanU8 number_of_bytes)
339 {
340     ZYAN_ASSERT(state);
341     ZYAN_ASSERT(instruction);
342     ZYAN_ASSERT(value);
343 
344     if (instruction->length + number_of_bytes > ZYDIS_MAX_INSTRUCTION_LENGTH)
345     {
346         return ZYDIS_STATUS_INSTRUCTION_TOO_LONG;
347     }
348 
349     if (state->buffer_len >= number_of_bytes)
350     {
351         instruction->length += number_of_bytes;
352 
353         ZYAN_MEMCPY(value, state->buffer, number_of_bytes);
354         state->buffer += number_of_bytes;
355         state->buffer_len -= number_of_bytes;
356 
357         return ZYAN_STATUS_SUCCESS;
358     }
359 
360     return ZYDIS_STATUS_NO_MORE_DATA;
361 }
362 
363 /* ---------------------------------------------------------------------------------------------- */
364 /* Decode functions                                                                               */
365 /* ---------------------------------------------------------------------------------------------- */
366 
367 /**
368  * Decodes the `REX`-prefix.
369  *
370  * @param   context     A pointer to the `ZydisDecoderContext` struct.
371  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
372  * @param   data        The `REX` byte.
373  */
374 static void ZydisDecodeREX(ZydisDecoderContext* context, ZydisDecodedInstruction* instruction,
375     ZyanU8 data)
376 {
377     ZYAN_ASSERT(instruction);
378     ZYAN_ASSERT((data & 0xF0) == 0x40);
379 
380     instruction->attributes |= ZYDIS_ATTRIB_HAS_REX;
381     instruction->raw.rex.W   = (data >> 3) & 0x01;
382     instruction->raw.rex.R   = (data >> 2) & 0x01;
383     instruction->raw.rex.X   = (data >> 1) & 0x01;
384     instruction->raw.rex.B   = (data >> 0) & 0x01;
385 
386     // Update internal fields
387     context->vector_unified.W = instruction->raw.rex.W;
388     context->vector_unified.R = instruction->raw.rex.R;
389     context->vector_unified.X = instruction->raw.rex.X;
390     context->vector_unified.B = instruction->raw.rex.B;
391 }
392 
393 /**
394  * Decodes the `XOP`-prefix.
395  *
396  * @param   context     A pointer to the `ZydisDecoderContext` struct.
397  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
398  * @param   data        The `XOP` bytes.
399  *
400  * @return  A zyan status code.
401  */
402 static ZyanStatus ZydisDecodeXOP(ZydisDecoderContext* context,
403     ZydisDecodedInstruction* instruction, const ZyanU8 data[3])
404 {
405     ZYAN_ASSERT(instruction);
406     ZYAN_ASSERT(data[0] == 0x8F);
407     ZYAN_ASSERT(((data[1] >> 0) & 0x1F) >= 8);
408     ZYAN_ASSERT(instruction->raw.xop.offset == instruction->length - 3);
409 
410     if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
411     {
412         // XOP is invalid in 16-bit real mode
413         return ZYDIS_STATUS_DECODING_ERROR;
414     }
415 
416     instruction->attributes |= ZYDIS_ATTRIB_HAS_XOP;
417     instruction->raw.xop.R       = (data[1] >> 7) & 0x01;
418     instruction->raw.xop.X       = (data[1] >> 6) & 0x01;
419     instruction->raw.xop.B       = (data[1] >> 5) & 0x01;
420     instruction->raw.xop.m_mmmm  = (data[1] >> 0) & 0x1F;
421 
422     if ((instruction->raw.xop.m_mmmm < 0x08) || (instruction->raw.xop.m_mmmm > 0x0A))
423     {
424         // Invalid according to the AMD documentation
425         return ZYDIS_STATUS_INVALID_MAP;
426     }
427 
428     instruction->raw.xop.W    = (data[2] >> 7) & 0x01;
429     instruction->raw.xop.vvvv = (data[2] >> 3) & 0x0F;
430     instruction->raw.xop.L    = (data[2] >> 2) & 0x01;
431     instruction->raw.xop.pp   = (data[2] >> 0) & 0x03;
432 
433     // Update internal fields
434     context->vector_unified.W    = instruction->raw.xop.W;
435     context->vector_unified.R    = 0x01 & ~instruction->raw.xop.R;
436     context->vector_unified.X    = 0x01 & ~instruction->raw.xop.X;
437     context->vector_unified.B    = 0x01 & ~instruction->raw.xop.B;
438     context->vector_unified.L    = instruction->raw.xop.L;
439     context->vector_unified.LL   = instruction->raw.xop.L;
440     context->vector_unified.vvvv = (0x0F & ~instruction->raw.xop.vvvv);
441 
442     return ZYAN_STATUS_SUCCESS;
443 }
444 
445 /**
446  * Decodes the `VEX`-prefix.
447  *
448  * @param   context     A pointer to the `ZydisDecoderContext` struct.
449  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
450  * @param   data        The `VEX` bytes.
451  *
452  * @return  A zyan status code.
453  */
454 static ZyanStatus ZydisDecodeVEX(ZydisDecoderContext* context,
455     ZydisDecodedInstruction* instruction, const ZyanU8 data[3])
456 {
457     ZYAN_ASSERT(instruction);
458     ZYAN_ASSERT((data[0] == 0xC4) || (data[0] == 0xC5));
459 
460     if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
461     {
462         // VEX is invalid in 16-bit real mode
463         return ZYDIS_STATUS_DECODING_ERROR;
464     }
465 
466     instruction->attributes |= ZYDIS_ATTRIB_HAS_VEX;
467     switch (data[0])
468     {
469     case 0xC4:
470         ZYAN_ASSERT(instruction->raw.vex.offset == instruction->length - 3);
471         instruction->raw.vex.size    = 3;
472         instruction->raw.vex.R       = (data[1] >> 7) & 0x01;
473         instruction->raw.vex.X       = (data[1] >> 6) & 0x01;
474         instruction->raw.vex.B       = (data[1] >> 5) & 0x01;
475         instruction->raw.vex.m_mmmm  = (data[1] >> 0) & 0x1F;
476         instruction->raw.vex.W       = (data[2] >> 7) & 0x01;
477         instruction->raw.vex.vvvv    = (data[2] >> 3) & 0x0F;
478         instruction->raw.vex.L       = (data[2] >> 2) & 0x01;
479         instruction->raw.vex.pp      = (data[2] >> 0) & 0x03;
480         break;
481     case 0xC5:
482         ZYAN_ASSERT(instruction->raw.vex.offset == instruction->length - 2);
483         instruction->raw.vex.size    = 2;
484         instruction->raw.vex.R       = (data[1] >> 7) & 0x01;
485         instruction->raw.vex.X       = 1;
486         instruction->raw.vex.B       = 1;
487         instruction->raw.vex.m_mmmm  = 1;
488         instruction->raw.vex.W       = 0;
489         instruction->raw.vex.vvvv    = (data[1] >> 3) & 0x0F;
490         instruction->raw.vex.L       = (data[1] >> 2) & 0x01;
491         instruction->raw.vex.pp      = (data[1] >> 0) & 0x03;
492         break;
493     default:
494         ZYAN_UNREACHABLE;
495     }
496 
497     // Map 0 is only valid for some KNC instructions
498 #ifdef ZYDIS_DISABLE_KNC
499     if ((instruction->raw.vex.m_mmmm == 0) || (instruction->raw.vex.m_mmmm > 0x03))
500 #else
501     if (instruction->raw.vex.m_mmmm > 0x03)
502 #endif
503     {
504         // Invalid according to the intel documentation
505         return ZYDIS_STATUS_INVALID_MAP;
506     }
507 
508     // Update internal fields
509     context->vector_unified.W    = instruction->raw.vex.W;
510     context->vector_unified.R    = 0x01 & ~instruction->raw.vex.R;
511     context->vector_unified.X    = 0x01 & ~instruction->raw.vex.X;
512     context->vector_unified.B    = 0x01 & ~instruction->raw.vex.B;
513     context->vector_unified.L    = instruction->raw.vex.L;
514     context->vector_unified.LL   = instruction->raw.vex.L;
515     context->vector_unified.vvvv = (0x0F & ~instruction->raw.vex.vvvv);
516 
517     return ZYAN_STATUS_SUCCESS;
518 }
519 
520 #ifndef ZYDIS_DISABLE_AVX512
521 /**
522  * Decodes the `EVEX`-prefix.
523  *
524  * @param   context     A pointer to the `ZydisDecoderContext` struct.
525  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
526  * @param   data        The `EVEX` bytes.
527  *
528  * @return  A zyan status code.
529  */
530 static ZyanStatus ZydisDecodeEVEX(ZydisDecoderContext* context,
531     ZydisDecodedInstruction* instruction, const ZyanU8 data[4])
532 {
533     ZYAN_ASSERT(instruction);
534     ZYAN_ASSERT(data[0] == 0x62);
535     ZYAN_ASSERT(instruction->raw.evex.offset == instruction->length - 4);
536 
537     if (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16)
538     {
539         // EVEX is invalid in 16-bit real mode
540         return ZYDIS_STATUS_DECODING_ERROR;
541     }
542 
543     instruction->attributes |= ZYDIS_ATTRIB_HAS_EVEX;
544     instruction->raw.evex.R         = (data[1] >> 7) & 0x01;
545     instruction->raw.evex.X         = (data[1] >> 6) & 0x01;
546     instruction->raw.evex.B         = (data[1] >> 5) & 0x01;
547     instruction->raw.evex.R2        = (data[1] >> 4) & 0x01;
548 
549     if (data[1] & 0x08)
550     {
551         // Invalid according to the intel documentation
552         return ZYDIS_STATUS_MALFORMED_EVEX;
553     }
554 
555     instruction->raw.evex.mmm       = (data[1] >> 0) & 0x07;
556 
557     if ((instruction->raw.evex.mmm == 0x00) ||
558         (instruction->raw.evex.mmm == 0x04) ||
559         (instruction->raw.evex.mmm == 0x07))
560     {
561         // Invalid according to the intel documentation
562         return ZYDIS_STATUS_INVALID_MAP;
563     }
564 
565     instruction->raw.evex.W         = (data[2] >> 7) & 0x01;
566     instruction->raw.evex.vvvv      = (data[2] >> 3) & 0x0F;
567 
568     ZYAN_ASSERT(((data[2] >> 2) & 0x01) == 0x01);
569 
570     instruction->raw.evex.pp        = (data[2] >> 0) & 0x03;
571     instruction->raw.evex.z         = (data[3] >> 7) & 0x01;
572     instruction->raw.evex.L2        = (data[3] >> 6) & 0x01;
573     instruction->raw.evex.L         = (data[3] >> 5) & 0x01;
574     instruction->raw.evex.b         = (data[3] >> 4) & 0x01;
575     instruction->raw.evex.V2        = (data[3] >> 3) & 0x01;
576 
577     if (!instruction->raw.evex.V2 &&
578         (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64))
579     {
580         return ZYDIS_STATUS_MALFORMED_EVEX;
581     }
582 
583     instruction->raw.evex.aaa       = (data[3] >> 0) & 0x07;
584 
585     if (instruction->raw.evex.z && !instruction->raw.evex.aaa)
586     {
587         return ZYDIS_STATUS_INVALID_MASK; // TODO: Dedicated status code
588     }
589 
590     // Update internal fields
591     context->vector_unified.W    = instruction->raw.evex.W;
592     context->vector_unified.R    = 0x01 & ~instruction->raw.evex.R;
593     context->vector_unified.X    = 0x01 & ~instruction->raw.evex.X;
594     context->vector_unified.B    = 0x01 & ~instruction->raw.evex.B;
595     context->vector_unified.LL   = (data[3] >> 5) & 0x03;
596     context->vector_unified.R2   = 0x01 & ~instruction->raw.evex.R2;
597     context->vector_unified.V2   = 0x01 & ~instruction->raw.evex.V2;
598     context->vector_unified.vvvv = 0x0F & ~instruction->raw.evex.vvvv;
599     context->vector_unified.mask = instruction->raw.evex.aaa;
600 
601     if (!instruction->raw.evex.V2 && (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64))
602     {
603         return ZYDIS_STATUS_MALFORMED_EVEX;
604     }
605     if (!instruction->raw.evex.b && (context->vector_unified.LL == 3))
606     {
607         // LL = 3 is only valid for instructions with embedded rounding control
608         return ZYDIS_STATUS_MALFORMED_EVEX;
609     }
610 
611     return ZYAN_STATUS_SUCCESS;
612 }
613 #endif
614 
615 #ifndef ZYDIS_DISABLE_KNC
616 /**
617  * Decodes the `MVEX`-prefix.
618  *
619  * @param   context     A pointer to the `ZydisDecoderContext` struct.
620  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
621  * @param   data        The `MVEX` bytes.
622  *
623  * @return  A zyan status code.
624  */
625 static ZyanStatus ZydisDecodeMVEX(ZydisDecoderContext* context,
626     ZydisDecodedInstruction* instruction, const ZyanU8 data[4])
627 {
628     ZYAN_ASSERT(instruction);
629     ZYAN_ASSERT(data[0] == 0x62);
630     ZYAN_ASSERT(instruction->raw.mvex.offset == instruction->length - 4);
631 
632     if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
633     {
634         // MVEX is only valid in 64-bit mode
635         return ZYDIS_STATUS_DECODING_ERROR;
636     }
637 
638     instruction->attributes |= ZYDIS_ATTRIB_HAS_MVEX;
639     instruction->raw.mvex.R    = (data[1] >> 7) & 0x01;
640     instruction->raw.mvex.X    = (data[1] >> 6) & 0x01;
641     instruction->raw.mvex.B    = (data[1] >> 5) & 0x01;
642     instruction->raw.mvex.R2   = (data[1] >> 4) & 0x01;
643     instruction->raw.mvex.mmmm = (data[1] >> 0) & 0x0F;
644 
645     if (instruction->raw.mvex.mmmm > 0x03)
646     {
647         // Invalid according to the intel documentation
648         return ZYDIS_STATUS_INVALID_MAP;
649     }
650 
651     instruction->raw.mvex.W    = (data[2] >> 7) & 0x01;
652     instruction->raw.mvex.vvvv = (data[2] >> 3) & 0x0F;
653 
654     ZYAN_ASSERT(((data[2] >> 2) & 0x01) == 0x00);
655 
656     instruction->raw.mvex.pp   = (data[2] >> 0) & 0x03;
657     instruction->raw.mvex.E    = (data[3] >> 7) & 0x01;
658     instruction->raw.mvex.SSS  = (data[3] >> 4) & 0x07;
659     instruction->raw.mvex.V2   = (data[3] >> 3) & 0x01;
660     instruction->raw.mvex.kkk  = (data[3] >> 0) & 0x07;
661 
662     // Update internal fields
663     context->vector_unified.W    = instruction->raw.mvex.W;
664     context->vector_unified.R    = 0x01 & ~instruction->raw.mvex.R;
665     context->vector_unified.X    = 0x01 & ~instruction->raw.mvex.X;
666     context->vector_unified.B    = 0x01 & ~instruction->raw.mvex.B;
667     context->vector_unified.R2   = 0x01 & ~instruction->raw.mvex.R2;
668     context->vector_unified.V2   = 0x01 & ~instruction->raw.mvex.V2;
669     context->vector_unified.LL   = 2;
670     context->vector_unified.vvvv = 0x0F & ~instruction->raw.mvex.vvvv;
671     context->vector_unified.mask = instruction->raw.mvex.kkk;
672 
673     return ZYAN_STATUS_SUCCESS;
674 }
675 #endif
676 
677 /**
678  * Decodes the `ModRM`-byte.
679  *
680  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
681  * @param   data        The `ModRM` byte.
682  */
683 static void ZydisDecodeModRM(ZydisDecodedInstruction* instruction, ZyanU8 data)
684 {
685     ZYAN_ASSERT(instruction);
686     ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM));
687     ZYAN_ASSERT(instruction->raw.modrm.offset == instruction->length - 1);
688 
689     instruction->attributes   |= ZYDIS_ATTRIB_HAS_MODRM;
690     instruction->raw.modrm.mod = (data >> 6) & 0x03;
691     instruction->raw.modrm.reg = (data >> 3) & 0x07;
692     instruction->raw.modrm.rm  = (data >> 0) & 0x07;
693 }
694 
695 /**
696  * Decodes the `SIB`-byte.
697  *
698  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct
699  * @param   data        The `SIB` byte.
700  */
701 static void ZydisDecodeSIB(ZydisDecodedInstruction* instruction, ZyanU8 data)
702 {
703     ZYAN_ASSERT(instruction);
704     ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM);
705     ZYAN_ASSERT(instruction->raw.modrm.rm == 4);
706     ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB));
707     ZYAN_ASSERT(instruction->raw.sib.offset == instruction->length - 1);
708 
709     instruction->attributes    |= ZYDIS_ATTRIB_HAS_SIB;
710     instruction->raw.sib.scale = (data >> 6) & 0x03;
711     instruction->raw.sib.index = (data >> 3) & 0x07;
712     instruction->raw.sib.base  = (data >> 0) & 0x07;
713 }
714 
715 /* ---------------------------------------------------------------------------------------------- */
716 
717 /**
718  * Reads a displacement value.
719  *
720  * @param   state       A pointer to the `ZydisDecoderState` struct.
721  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
722  * @param   size        The physical size of the displacement value.
723  *
724  * @return  A zyan status code.
725  */
726 static ZyanStatus ZydisReadDisplacement(ZydisDecoderState* state,
727     ZydisDecodedInstruction* instruction, ZyanU8 size)
728 {
729     ZYAN_ASSERT(state);
730     ZYAN_ASSERT(instruction);
731     ZYAN_ASSERT(instruction->raw.disp.size == 0);
732 
733     instruction->raw.disp.size = size;
734     instruction->raw.disp.offset = instruction->length;
735 
736     switch (size)
737     {
738     case 8:
739     {
740         ZyanU8 value;
741         ZYAN_CHECK(ZydisInputNext(state, instruction, &value));
742         instruction->raw.disp.value = *(ZyanI8*)&value;
743         break;
744     }
745     case 16:
746     {
747         ZyanU16 value;
748         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 2));
749         instruction->raw.disp.value = *(ZyanI16*)&value;
750         break;
751     }
752     case 32:
753     {
754         ZyanU32 value;
755         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 4));
756         instruction->raw.disp.value = *(ZyanI32*)&value;
757         break;
758     }
759     case 64:
760     {
761         ZyanU64 value;
762         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 8));
763         instruction->raw.disp.value = *(ZyanI64*)&value;
764         break;
765     }
766     default:
767         ZYAN_UNREACHABLE;
768     }
769 
770     // TODO: Fix endianess on big-endian systems
771 
772     return ZYAN_STATUS_SUCCESS;
773 }
774 
775 /**
776  * Reads an immediate value.
777  *
778  * @param   state       A pointer to the `ZydisDecoderState` struct.
779  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
780  * @param   id          The immediate id (either `0` or `1`).
781  * @param   size        The physical size of the immediate value.
782  * @param   is_signed   Signals, if the immediate value is signed.
783  * @param   is_relative Signals, if the immediate value is a relative offset.
784  *
785  * @return  A zyan status code.
786  */
787 static ZyanStatus ZydisReadImmediate(ZydisDecoderState* state,
788     ZydisDecodedInstruction* instruction, ZyanU8 id, ZyanU8 size, ZyanBool is_signed,
789     ZyanBool is_relative)
790 {
791     ZYAN_ASSERT(state);
792     ZYAN_ASSERT(instruction);
793     ZYAN_ASSERT((id == 0) || (id == 1));
794     ZYAN_ASSERT(is_signed || !is_relative);
795     ZYAN_ASSERT(instruction->raw.imm[id].size == 0);
796 
797     instruction->raw.imm[id].size = size;
798     instruction->raw.imm[id].offset = instruction->length;
799     instruction->raw.imm[id].is_signed = is_signed;
800     instruction->raw.imm[id].is_relative = is_relative;
801     switch (size)
802     {
803     case 8:
804     {
805         ZyanU8 value;
806         ZYAN_CHECK(ZydisInputNext(state, instruction, &value));
807         if (is_signed)
808         {
809             instruction->raw.imm[id].value.s = (ZyanI8)value;
810         } else
811         {
812             instruction->raw.imm[id].value.u = value;
813         }
814         break;
815     }
816     case 16:
817     {
818         ZyanU16 value;
819         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 2));
820         if (is_signed)
821         {
822             instruction->raw.imm[id].value.s = (ZyanI16)value;
823         } else
824         {
825             instruction->raw.imm[id].value.u = value;
826         }
827         break;
828     }
829     case 32:
830     {
831         ZyanU32 value;
832         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 4));
833         if (is_signed)
834         {
835             instruction->raw.imm[id].value.s = (ZyanI32)value;
836         } else
837         {
838             instruction->raw.imm[id].value.u = value;
839         }
840         break;
841     }
842     case 64:
843     {
844         ZyanU64 value;
845         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, (ZyanU8*)&value, 8));
846         if (is_signed)
847         {
848             instruction->raw.imm[id].value.s = (ZyanI64)value;
849         } else
850         {
851             instruction->raw.imm[id].value.u = value;
852         }
853         break;
854     }
855     default:
856         ZYAN_UNREACHABLE;
857     }
858 
859     // TODO: Fix endianess on big-endian systems
860 
861     return ZYAN_STATUS_SUCCESS;
862 }
863 
864 /* ---------------------------------------------------------------------------------------------- */
865 /* Semantic instruction decoding                                                                  */
866 /* ---------------------------------------------------------------------------------------------- */
867 
868 #ifndef ZYDIS_MINIMAL_MODE
869 /**
870  * Calculates the register-id for a specific register-encoding and register-class.
871  *
872  * @param   context         A pointer to the `ZydisDecoderContext` struct.
873  * @param   instruction     A pointer to the ` ZydisDecodedInstruction` struct.
874  * @param   encoding        The register-encoding.
875  * @param   register_class  The register-class.
876  *
877  * @return  A zyan status code.
878  *
879  * This function calculates the register-id by combining different fields and flags of previously
880  * decoded structs.
881  */
882 static ZyanU8 ZydisCalcRegisterId(const ZydisDecoderContext* context,
883     const ZydisDecodedInstruction* instruction, ZydisRegisterEncoding encoding,
884     ZydisRegisterClass register_class)
885 {
886     ZYAN_ASSERT(context);
887     ZYAN_ASSERT(instruction);
888 
889     // TODO: Combine OPCODE and IS4 in `ZydisPopulateRegisterIds` and get rid of this
890     // TODO: function entirely
891 
892     switch (encoding)
893     {
894     case ZYDIS_REG_ENCODING_REG:
895         return context->reg_info.id_reg;
896     case ZYDIS_REG_ENCODING_NDSNDD:
897         return context->reg_info.id_ndsndd;
898     case ZYDIS_REG_ENCODING_RM:
899         return context->reg_info.id_rm;
900     case ZYDIS_REG_ENCODING_BASE:
901         return context->reg_info.id_base;
902     case ZYDIS_REG_ENCODING_INDEX:
903     case ZYDIS_REG_ENCODING_VIDX:
904         return context->reg_info.id_index;
905     case ZYDIS_REG_ENCODING_OPCODE:
906     {
907         ZYAN_ASSERT((register_class == ZYDIS_REGCLASS_GPR8) ||
908                     (register_class == ZYDIS_REGCLASS_GPR16) ||
909                     (register_class == ZYDIS_REGCLASS_GPR32) ||
910                     (register_class == ZYDIS_REGCLASS_GPR64));
911         ZyanU8 value = (instruction->opcode & 0x0F);
912         if (value > 7)
913         {
914             value = value - 8;
915         }
916         if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
917         {
918             return value;
919         }
920         return value | (context->vector_unified.B << 3);
921     }
922     case ZYDIS_REG_ENCODING_IS4:
923     {
924         if (instruction->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
925         {
926             return (instruction->raw.imm[0].value.u >> 4) & 0x07;
927         }
928         ZyanU8 value = (instruction->raw.imm[0].value.u >> 4) & 0x0F;
929         // We have to check the instruction-encoding, because the extension by bit [3] is only
930         // valid for EVEX and MVEX instructions
931         if ((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
932             (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
933         {
934             switch (register_class)
935             {
936             case ZYDIS_REGCLASS_XMM:
937             case ZYDIS_REGCLASS_YMM:
938             case ZYDIS_REGCLASS_ZMM:
939                 value |= ((instruction->raw.imm[0].value.u & 0x08) << 1);
940             default:
941                 break;
942             }
943         }
944         return value;
945     }
946     case ZYDIS_REG_ENCODING_MASK:
947         return context->vector_unified.mask;
948     default:
949         ZYAN_UNREACHABLE;
950     }
951 }
952 #endif
953 
954 #ifndef ZYDIS_MINIMAL_MODE
955 /**
956  * Sets the operand-size and element-specific information for the given operand.
957  *
958  * @param   context         A pointer to the `ZydisDecoderContext` struct.
959  * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
960  * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
961  * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
962  */
963 static void ZydisSetOperandSizeAndElementInfo(const ZydisDecoderContext* context,
964     const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operand,
965     const ZydisOperandDefinition* definition)
966 {
967     ZYAN_ASSERT(context);
968     ZYAN_ASSERT(instruction);
969     ZYAN_ASSERT(operand);
970     ZYAN_ASSERT(definition);
971 
972     // Operand size
973     switch (operand->type)
974     {
975     case ZYDIS_OPERAND_TYPE_REGISTER:
976     {
977         if (definition->size[context->eosz_index])
978         {
979             operand->size = definition->size[context->eosz_index] * 8;
980         } else
981         {
982             operand->size = ZydisRegisterGetWidth(instruction->machine_mode,
983                 operand->reg.value);
984         }
985         operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
986         operand->element_size = operand->size;
987         break;
988     }
989     case ZYDIS_OPERAND_TYPE_MEMORY:
990         switch (instruction->encoding)
991         {
992         case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
993         case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
994         case ZYDIS_INSTRUCTION_ENCODING_XOP:
995         case ZYDIS_INSTRUCTION_ENCODING_VEX:
996             if (operand->mem.type == ZYDIS_MEMOP_TYPE_AGEN)
997             {
998                 ZYAN_ASSERT(definition->size[context->eosz_index] == 0);
999                 operand->size = instruction->address_width;
1000                 operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1001             } else
1002             {
1003                 ZYAN_ASSERT(definition->size[context->eosz_index] ||
1004                     (instruction->meta.category == ZYDIS_CATEGORY_AMX_TILE));
1005                 operand->size = definition->size[context->eosz_index] * 8;
1006             }
1007             break;
1008         case ZYDIS_INSTRUCTION_ENCODING_EVEX:
1009 #ifndef ZYDIS_DISABLE_AVX512
1010             if (definition->size[context->eosz_index])
1011             {
1012                 // Operand size is hardcoded
1013                 operand->size = definition->size[context->eosz_index] * 8;
1014             } else
1015             {
1016                 // Operand size depends on the tuple-type, the element-size and the number of
1017                 // elements
1018                 ZYAN_ASSERT(instruction->avx.vector_length);
1019                 ZYAN_ASSERT(context->evex.element_size);
1020                 switch (context->evex.tuple_type)
1021                 {
1022                 case ZYDIS_TUPLETYPE_FV:
1023                     if (instruction->avx.broadcast.mode)
1024                     {
1025                         operand->size = context->evex.element_size;
1026                     } else
1027                     {
1028                         operand->size = instruction->avx.vector_length;
1029                     }
1030                     break;
1031                 case ZYDIS_TUPLETYPE_HV:
1032                     if (instruction->avx.broadcast.mode)
1033                     {
1034                         operand->size = context->evex.element_size;
1035                     } else
1036                     {
1037                         operand->size = (ZyanU16)instruction->avx.vector_length / 2;
1038                     }
1039                     break;
1040                 case ZYDIS_TUPLETYPE_QUARTER:
1041                     if (instruction->avx.broadcast.mode)
1042                     {
1043                         operand->size = context->evex.element_size;
1044                     }
1045                     else
1046                     {
1047                         operand->size = (ZyanU16)instruction->avx.vector_length / 4;
1048                     }
1049                     break;
1050                 default:
1051                     ZYAN_UNREACHABLE;
1052                 }
1053             }
1054             ZYAN_ASSERT(operand->size);
1055 #else
1056             ZYAN_UNREACHABLE;
1057 #endif
1058             break;
1059         case ZYDIS_INSTRUCTION_ENCODING_MVEX:
1060 #ifndef ZYDIS_DISABLE_KNC
1061             if (definition->size[context->eosz_index])
1062             {
1063                 // Operand size is hardcoded
1064                 operand->size = definition->size[context->eosz_index] * 8;
1065             } else
1066             {
1067                 ZYAN_ASSERT(definition->element_type == ZYDIS_IELEMENT_TYPE_VARIABLE);
1068                 ZYAN_ASSERT(instruction->avx.vector_length == 512);
1069 
1070                 switch (instruction->avx.conversion.mode)
1071                 {
1072                 case ZYDIS_CONVERSION_MODE_INVALID:
1073                     operand->size = 512;
1074                     switch (context->mvex.functionality)
1075                     {
1076                     case ZYDIS_MVEX_FUNC_SF_32:
1077                     case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
1078                     case ZYDIS_MVEX_FUNC_UF_32:
1079                     case ZYDIS_MVEX_FUNC_DF_32:
1080                         operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT32;
1081                         operand->element_size = 32;
1082                         break;
1083                     case ZYDIS_MVEX_FUNC_SF_32_BCST:
1084                         operand->size = 256;
1085                         operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT32;
1086                         operand->element_size = 32;
1087                         break;
1088                     case ZYDIS_MVEX_FUNC_SI_32:
1089                     case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
1090                     case ZYDIS_MVEX_FUNC_UI_32:
1091                     case ZYDIS_MVEX_FUNC_DI_32:
1092                         operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1093                         operand->element_size = 32;
1094                         break;
1095                     case ZYDIS_MVEX_FUNC_SI_32_BCST:
1096                         operand->size = 256;
1097                         operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1098                         operand->element_size = 32;
1099                         break;
1100                     case ZYDIS_MVEX_FUNC_SF_64:
1101                     case ZYDIS_MVEX_FUNC_UF_64:
1102                     case ZYDIS_MVEX_FUNC_DF_64:
1103                         operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT64;
1104                         operand->element_size = 64;
1105                         break;
1106                     case ZYDIS_MVEX_FUNC_SI_64:
1107                     case ZYDIS_MVEX_FUNC_UI_64:
1108                     case ZYDIS_MVEX_FUNC_DI_64:
1109                         operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1110                         operand->element_size = 64;
1111                         break;
1112                     default:
1113                         ZYAN_UNREACHABLE;
1114                     }
1115                     break;
1116                 case ZYDIS_CONVERSION_MODE_FLOAT16:
1117                     operand->size = 256;
1118                     operand->element_type = ZYDIS_ELEMENT_TYPE_FLOAT16;
1119                     operand->element_size = 16;
1120                     break;
1121                 case ZYDIS_CONVERSION_MODE_SINT16:
1122                     operand->size = 256;
1123                     operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1124                     operand->element_size = 16;
1125                     break;
1126                 case ZYDIS_CONVERSION_MODE_UINT16:
1127                     operand->size = 256;
1128                     operand->element_type = ZYDIS_ELEMENT_TYPE_UINT;
1129                     operand->element_size = 16;
1130                     break;
1131                 case ZYDIS_CONVERSION_MODE_SINT8:
1132                     operand->size = 128;
1133                     operand->element_type = ZYDIS_ELEMENT_TYPE_INT;
1134                     operand->element_size = 8;
1135                     break;
1136                 case ZYDIS_CONVERSION_MODE_UINT8:
1137                     operand->size = 128;
1138                     operand->element_type = ZYDIS_ELEMENT_TYPE_UINT;
1139                     operand->element_size = 8;
1140                     break;
1141                 default:
1142                     ZYAN_UNREACHABLE;
1143                 }
1144 
1145                 switch (instruction->avx.broadcast.mode)
1146                 {
1147                 case ZYDIS_BROADCAST_MODE_INVALID:
1148                     // Nothing to do here
1149                     break;
1150                 case ZYDIS_BROADCAST_MODE_1_TO_8:
1151                 case ZYDIS_BROADCAST_MODE_1_TO_16:
1152                     operand->size = operand->element_size;
1153                     break;
1154                 case ZYDIS_BROADCAST_MODE_4_TO_8:
1155                 case ZYDIS_BROADCAST_MODE_4_TO_16:
1156                     operand->size = operand->element_size * 4;
1157                     break;
1158                 default:
1159                     ZYAN_UNREACHABLE;
1160                 }
1161             }
1162 #else
1163             ZYAN_UNREACHABLE;
1164 #endif
1165             break;
1166         default:
1167             ZYAN_UNREACHABLE;
1168         }
1169         break;
1170     case ZYDIS_OPERAND_TYPE_POINTER:
1171         ZYAN_ASSERT((instruction->raw.imm[0].size == 16) ||
1172                     (instruction->raw.imm[0].size == 32));
1173         ZYAN_ASSERT( instruction->raw.imm[1].size == 16);
1174         operand->size = instruction->raw.imm[0].size + instruction->raw.imm[1].size;
1175         break;
1176     case ZYDIS_OPERAND_TYPE_IMMEDIATE:
1177         operand->size = definition->size[context->eosz_index] * 8;
1178         break;
1179     default:
1180         ZYAN_UNREACHABLE;
1181     }
1182 
1183     // Element-type and -size
1184     if (definition->element_type && (definition->element_type != ZYDIS_IELEMENT_TYPE_VARIABLE))
1185     {
1186         ZydisGetElementInfo(definition->element_type, &operand->element_type,
1187             &operand->element_size);
1188         if (!operand->element_size)
1189         {
1190             // The element size is the same as the operand size. This is used for single element
1191             // scaling operands
1192             operand->element_size = operand->size;
1193         }
1194     }
1195 
1196     // Element count
1197     if (operand->element_size && operand->size && (operand->element_type != ZYDIS_ELEMENT_TYPE_CC))
1198     {
1199         operand->element_count = operand->size / operand->element_size;
1200     } else
1201     {
1202         operand->element_count = 1;
1203     }
1204 }
1205 #endif
1206 
1207 #ifndef ZYDIS_MINIMAL_MODE
1208 /**
1209  * Decodes an register-operand.
1210  *
1211  * @param   instruction      A pointer to the `ZydisDecodedInstruction` struct.
1212  * @param   operand          A pointer to the `ZydisDecodedOperand` struct.
1213  * @param   register_class   The register class.
1214  * @param   register_id      The register id.
1215  *
1216  * @return  A zyan status code.
1217  */
1218 static ZyanStatus ZydisDecodeOperandRegister(const ZydisDecodedInstruction* instruction,
1219     ZydisDecodedOperand* operand, ZydisRegisterClass register_class, ZyanU8 register_id)
1220 {
1221     ZYAN_ASSERT(instruction);
1222     ZYAN_ASSERT(operand);
1223 
1224     operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
1225 
1226     if (register_class == ZYDIS_REGCLASS_GPR8)
1227     {
1228         if ((instruction->attributes & ZYDIS_ATTRIB_HAS_REX) && (register_id >= 4))
1229         {
1230             operand->reg.value = ZYDIS_REGISTER_SPL + (register_id - 4);
1231         } else
1232         {
1233             operand->reg.value = ZYDIS_REGISTER_AL + register_id;
1234         }
1235     } else
1236     {
1237         operand->reg.value = ZydisRegisterEncode(register_class, register_id);
1238         ZYAN_ASSERT(operand->reg.value);
1239         /*if (!operand->reg.value)
1240         {
1241             return ZYAN_STATUS_BAD_REGISTER;
1242         }*/
1243     }
1244 
1245     return ZYAN_STATUS_SUCCESS;
1246 }
1247 #endif
1248 
1249 #ifndef ZYDIS_MINIMAL_MODE
1250 /**
1251  * Decodes a memory operand.
1252  *
1253  * @param   context             A pointer to the `ZydisDecoderContext` struct.
1254  * @param   instruction         A pointer to the `ZydisDecodedInstruction` struct.
1255  * @param   operand             A pointer to the `ZydisDecodedOperand` struct.
1256  * @param   vidx_register_class The register-class to use as the index register-class for
1257  *                              instructions with `VSIB` addressing.
1258  *
1259  * @return  A zyan status code.
1260  */
1261 static ZyanStatus ZydisDecodeOperandMemory(const ZydisDecoderContext* context,
1262     const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operand,
1263     ZydisRegisterClass vidx_register_class)
1264 {
1265     ZYAN_ASSERT(context);
1266     ZYAN_ASSERT(instruction);
1267     ZYAN_ASSERT(operand);
1268     ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MODRM);
1269     ZYAN_ASSERT(instruction->raw.modrm.mod != 3);
1270     ZYAN_ASSERT(!vidx_register_class || ((instruction->raw.modrm.rm == 4) &&
1271         ((instruction->address_width == 32) || (instruction->address_width == 64))));
1272 
1273     operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
1274     operand->mem.type = ZYDIS_MEMOP_TYPE_MEM;
1275 
1276     const ZyanU8 modrm_rm = instruction->raw.modrm.rm;
1277     ZyanU8 displacement_size = 0;
1278     switch (instruction->address_width)
1279     {
1280     case 16:
1281     {
1282         static const ZydisRegister bases[] =
1283         {
1284             ZYDIS_REGISTER_BX,   ZYDIS_REGISTER_BX,   ZYDIS_REGISTER_BP,   ZYDIS_REGISTER_BP,
1285             ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,   ZYDIS_REGISTER_BP,   ZYDIS_REGISTER_BX
1286         };
1287         static const ZydisRegister indices[] =
1288         {
1289             ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,   ZYDIS_REGISTER_SI,   ZYDIS_REGISTER_DI,
1290             ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE, ZYDIS_REGISTER_NONE
1291         };
1292         operand->mem.base = bases[modrm_rm];
1293         operand->mem.index = indices[modrm_rm];
1294         operand->mem.scale = (operand->mem.index == ZYDIS_REGISTER_NONE) ? 0 : 1;
1295         switch (instruction->raw.modrm.mod)
1296         {
1297         case 0:
1298             if (modrm_rm == 6)
1299             {
1300                 displacement_size = 16;
1301                 operand->mem.base = ZYDIS_REGISTER_NONE;
1302             }
1303             break;
1304         case 1:
1305             displacement_size = 8;
1306             break;
1307         case 2:
1308             displacement_size = 16;
1309             break;
1310         default:
1311             ZYAN_UNREACHABLE;
1312         }
1313         break;
1314     }
1315     case 32:
1316     {
1317         operand->mem.base = ZYDIS_REGISTER_EAX + ZydisCalcRegisterId(context, instruction,
1318             ZYDIS_REG_ENCODING_BASE, ZYDIS_REGCLASS_GPR32);
1319         switch (instruction->raw.modrm.mod)
1320         {
1321         case 0:
1322             if (modrm_rm == 5)
1323             {
1324                 if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
1325                 {
1326                     operand->mem.base = ZYDIS_REGISTER_EIP;
1327                 } else
1328                 {
1329                     operand->mem.base = ZYDIS_REGISTER_NONE;
1330                 }
1331                 displacement_size = 32;
1332             }
1333             break;
1334         case 1:
1335             displacement_size = 8;
1336             break;
1337         case 2:
1338             displacement_size = 32;
1339             break;
1340         default:
1341             ZYAN_UNREACHABLE;
1342         }
1343         if (modrm_rm == 4)
1344         {
1345             ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB);
1346             operand->mem.index =
1347                 ZydisRegisterEncode(vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR32,
1348                     ZydisCalcRegisterId(context, instruction,
1349                         vidx_register_class ? ZYDIS_REG_ENCODING_VIDX : ZYDIS_REG_ENCODING_INDEX,
1350                         vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR32));
1351             operand->mem.scale = (1 << instruction->raw.sib.scale);
1352             if (operand->mem.index == ZYDIS_REGISTER_ESP)
1353             {
1354                 operand->mem.index = ZYDIS_REGISTER_NONE;
1355                 operand->mem.scale = 0;
1356             }
1357             if (operand->mem.base == ZYDIS_REGISTER_EBP)
1358             {
1359                 if (instruction->raw.modrm.mod == 0)
1360                 {
1361                     operand->mem.base = ZYDIS_REGISTER_NONE;
1362                 }
1363                 displacement_size = (instruction->raw.modrm.mod == 1) ? 8 : 32;
1364             }
1365         } else
1366         {
1367             operand->mem.index = ZYDIS_REGISTER_NONE;
1368             operand->mem.scale = 0;
1369         }
1370         break;
1371     }
1372     case 64:
1373     {
1374         operand->mem.base = ZYDIS_REGISTER_RAX + ZydisCalcRegisterId(context, instruction,
1375             ZYDIS_REG_ENCODING_BASE, ZYDIS_REGCLASS_GPR64);
1376         switch (instruction->raw.modrm.mod)
1377         {
1378         case 0:
1379             if (modrm_rm == 5)
1380             {
1381                 if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
1382                 {
1383                     operand->mem.base = ZYDIS_REGISTER_RIP;
1384                 } else
1385                 {
1386                     operand->mem.base = ZYDIS_REGISTER_NONE;
1387                 }
1388                 displacement_size = 32;
1389             }
1390             break;
1391         case 1:
1392             displacement_size = 8;
1393             break;
1394         case 2:
1395             displacement_size = 32;
1396             break;
1397         default:
1398             ZYAN_UNREACHABLE;
1399         }
1400         if ((modrm_rm & 0x07) == 4)
1401         {
1402             ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_SIB);
1403             operand->mem.index =
1404                 ZydisRegisterEncode(vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR64,
1405                     ZydisCalcRegisterId(context, instruction,
1406                         vidx_register_class ? ZYDIS_REG_ENCODING_VIDX : ZYDIS_REG_ENCODING_INDEX,
1407                         vidx_register_class ? vidx_register_class : ZYDIS_REGCLASS_GPR64));
1408             operand->mem.scale = (1 << instruction->raw.sib.scale);
1409             if (operand->mem.index == ZYDIS_REGISTER_RSP)
1410             {
1411                 operand->mem.index = ZYDIS_REGISTER_NONE;
1412                 operand->mem.scale = 0;
1413             }
1414             if ((operand->mem.base == ZYDIS_REGISTER_RBP) ||
1415                 (operand->mem.base == ZYDIS_REGISTER_R13))
1416             {
1417                 if (instruction->raw.modrm.mod == 0)
1418                 {
1419                     operand->mem.base = ZYDIS_REGISTER_NONE;
1420                 }
1421                 displacement_size = (instruction->raw.modrm.mod == 1) ? 8 : 32;
1422             }
1423         } else
1424         {
1425             operand->mem.index = ZYDIS_REGISTER_NONE;
1426             operand->mem.scale = 0;
1427         }
1428         break;
1429     }
1430     default:
1431         ZYAN_UNREACHABLE;
1432     }
1433     if (displacement_size)
1434     {
1435         ZYAN_ASSERT(instruction->raw.disp.size == displacement_size);
1436         operand->mem.disp.has_displacement = ZYAN_TRUE;
1437         operand->mem.disp.value = instruction->raw.disp.value;
1438     }
1439     return ZYAN_STATUS_SUCCESS;
1440 }
1441 #endif
1442 
1443 #ifndef ZYDIS_MINIMAL_MODE
1444 /**
1445  * Decodes an implicit register operand.
1446  *
1447  * @param   decoder         A pointer to the `ZydisDecoder` instance.
1448  * @param   context         A pointer to the `ZydisDecoderContext` struct.
1449  * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
1450  * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
1451  * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
1452  */
1453 static void ZydisDecodeOperandImplicitRegister(const ZydisDecoder* decoder,
1454     const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
1455     ZydisDecodedOperand* operand, const ZydisOperandDefinition* definition)
1456 {
1457     ZYAN_ASSERT(context);
1458     ZYAN_ASSERT(instruction);
1459     ZYAN_ASSERT(operand);
1460     ZYAN_ASSERT(definition);
1461 
1462     operand->type = ZYDIS_OPERAND_TYPE_REGISTER;
1463 
1464     switch (definition->op.reg.type)
1465     {
1466     case ZYDIS_IMPLREG_TYPE_STATIC:
1467         operand->reg.value = definition->op.reg.reg.reg;
1468         break;
1469     case ZYDIS_IMPLREG_TYPE_GPR_OSZ:
1470     {
1471         static const ZydisRegisterClass lookup[3] =
1472         {
1473             ZYDIS_REGCLASS_GPR16,
1474             ZYDIS_REGCLASS_GPR32,
1475             ZYDIS_REGCLASS_GPR64
1476         };
1477         operand->reg.value =
1478             ZydisRegisterEncode(lookup[context->eosz_index], definition->op.reg.reg.id);
1479         break;
1480     }
1481     case ZYDIS_IMPLREG_TYPE_GPR_ASZ:
1482         operand->reg.value = ZydisRegisterEncode(
1483             (instruction->address_width    == 16) ? ZYDIS_REGCLASS_GPR16  :
1484             (instruction->address_width    == 32) ? ZYDIS_REGCLASS_GPR32  : ZYDIS_REGCLASS_GPR64,
1485             definition->op.reg.reg.id);
1486         break;
1487     case ZYDIS_IMPLREG_TYPE_IP_ASZ:
1488         operand->reg.value =
1489             (instruction->address_width    == 16) ? ZYDIS_REGISTER_IP     :
1490             (instruction->address_width    == 32) ? ZYDIS_REGISTER_EIP    : ZYDIS_REGISTER_RIP;
1491         break;
1492     case ZYDIS_IMPLREG_TYPE_GPR_SSZ:
1493         operand->reg.value = ZydisRegisterEncode(
1494             (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGCLASS_GPR16 :
1495             (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGCLASS_GPR32 :
1496                                                              ZYDIS_REGCLASS_GPR64,
1497             definition->op.reg.reg.id);
1498         break;
1499     case ZYDIS_IMPLREG_TYPE_IP_SSZ:
1500         operand->reg.value =
1501             (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGISTER_EIP    :
1502             (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGISTER_EIP    :
1503                                                              ZYDIS_REGISTER_RIP;
1504         break;
1505     case ZYDIS_IMPLREG_TYPE_FLAGS_SSZ:
1506         operand->reg.value =
1507             (decoder->stack_width == ZYDIS_STACK_WIDTH_16) ? ZYDIS_REGISTER_FLAGS  :
1508             (decoder->stack_width == ZYDIS_STACK_WIDTH_32) ? ZYDIS_REGISTER_EFLAGS :
1509                                                              ZYDIS_REGISTER_RFLAGS;
1510         break;
1511     default:
1512         ZYAN_UNREACHABLE;
1513     }
1514 }
1515 #endif
1516 
1517 #ifndef ZYDIS_MINIMAL_MODE
1518 /**
1519  * Decodes an implicit memory operand.
1520  *
1521  * @param   decoder         A pointer to the `ZydisDecoder` instance.
1522  * @param   context         A pointer to the `ZydisDecoderContext` struct.
1523  * @param   instruction     A pointer to the `ZydisDecodedInstruction` struct.
1524  * @param   operand         A pointer to the `ZydisDecodedOperand` struct.
1525  * @param   definition      A pointer to the `ZydisOperandDefinition` struct.
1526  */
1527 static void ZydisDecodeOperandImplicitMemory(const ZydisDecoder* decoder,
1528     const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
1529     ZydisDecodedOperand* operand, const ZydisOperandDefinition* definition)
1530 {
1531     ZYAN_ASSERT(context);
1532     ZYAN_ASSERT(operand);
1533     ZYAN_ASSERT(definition);
1534 
1535     static const ZydisRegisterClass lookup[3] =
1536     {
1537         ZYDIS_REGCLASS_GPR16,
1538         ZYDIS_REGCLASS_GPR32,
1539         ZYDIS_REGCLASS_GPR64
1540     };
1541 
1542     operand->type = ZYDIS_OPERAND_TYPE_MEMORY;
1543     operand->mem.type = ZYDIS_MEMOP_TYPE_MEM;
1544 
1545     switch (definition->op.mem.base)
1546     {
1547     case ZYDIS_IMPLMEM_BASE_AGPR_REG:
1548         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index],
1549             ZydisCalcRegisterId(context, instruction, ZYDIS_REG_ENCODING_REG,
1550                 lookup[context->easz_index]));
1551         break;
1552     case ZYDIS_IMPLMEM_BASE_AGPR_RM:
1553         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index],
1554             ZydisCalcRegisterId(context, instruction, ZYDIS_REG_ENCODING_RM,
1555                 lookup[context->easz_index]));
1556         break;
1557     case ZYDIS_IMPLMEM_BASE_AAX:
1558         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 0);
1559         break;
1560     case ZYDIS_IMPLMEM_BASE_ADX:
1561         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 2);
1562         break;
1563     case ZYDIS_IMPLMEM_BASE_ABX:
1564         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 3);
1565         break;
1566     case ZYDIS_IMPLMEM_BASE_ASI:
1567         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 6);
1568         break;
1569     case ZYDIS_IMPLMEM_BASE_ADI:
1570         operand->mem.base = ZydisRegisterEncode(lookup[context->easz_index], 7);
1571         break;
1572     case ZYDIS_IMPLMEM_BASE_SSP:
1573         operand->mem.base = ZydisRegisterEncode(lookup[decoder->stack_width], 4);
1574         break;
1575     case ZYDIS_IMPLMEM_BASE_SBP:
1576         operand->mem.base = ZydisRegisterEncode(lookup[decoder->stack_width], 5);
1577         break;
1578     default:
1579         ZYAN_UNREACHABLE;
1580     }
1581 
1582     if (definition->op.mem.seg)
1583     {
1584         operand->mem.segment =
1585             ZydisRegisterEncode(ZYDIS_REGCLASS_SEGMENT, definition->op.mem.seg - 1);
1586         ZYAN_ASSERT(operand->mem.segment);
1587     }
1588 }
1589 #endif
1590 
1591 #ifndef ZYDIS_MINIMAL_MODE
1592 static ZyanStatus ZydisDecodeOperands(const ZydisDecoder* decoder, const ZydisDecoderContext* context,
1593     const ZydisDecodedInstruction* instruction, ZydisDecodedOperand* operands, ZyanU8 operand_count)
1594 {
1595     ZYAN_ASSERT(decoder);
1596     ZYAN_ASSERT(context);
1597     ZYAN_ASSERT(context->definition);
1598     ZYAN_ASSERT(instruction);
1599     ZYAN_ASSERT(operands);
1600     ZYAN_ASSERT(operand_count);
1601     ZYAN_ASSERT(operand_count <= instruction->operand_count);
1602 
1603     const ZydisInstructionDefinition* definition = context->definition;
1604     const ZydisOperandDefinition* operand = ZydisGetOperandDefinitions(definition);
1605 
1606     ZYAN_MEMSET(operands, 0, sizeof(ZydisDecodedOperand) * operand_count);
1607 
1608     ZyanU8 imm_id = 0;
1609     for (ZyanU8 i = 0; i < operand_count; ++i)
1610     {
1611         ZydisRegisterClass register_class = ZYDIS_REGCLASS_INVALID;
1612 
1613         operands[i].id = i;
1614         operands[i].visibility = operand->visibility;
1615         operands[i].actions = operand->actions;
1616         ZYAN_ASSERT(!(operand->actions &
1617             ZYDIS_OPERAND_ACTION_READ & ZYDIS_OPERAND_ACTION_CONDREAD) ||
1618             (operand->actions & ZYDIS_OPERAND_ACTION_READ) ^
1619             (operand->actions & ZYDIS_OPERAND_ACTION_CONDREAD));
1620         ZYAN_ASSERT(!(operand->actions &
1621             ZYDIS_OPERAND_ACTION_WRITE & ZYDIS_OPERAND_ACTION_CONDWRITE) ||
1622             (operand->actions & ZYDIS_OPERAND_ACTION_WRITE) ^
1623             (operand->actions & ZYDIS_OPERAND_ACTION_CONDWRITE));
1624 
1625         // Implicit operands
1626         switch (operand->type)
1627         {
1628         case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_REG:
1629             ZydisDecodeOperandImplicitRegister(decoder, context, instruction, &operands[i], operand);
1630             break;
1631         case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_MEM:
1632             ZydisDecodeOperandImplicitMemory(decoder, context, instruction, &operands[i], operand);
1633             break;
1634         case ZYDIS_SEMANTIC_OPTYPE_IMPLICIT_IMM1:
1635             operands[i].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
1636             operands[i].size = 8;
1637             operands[i].imm.value.u = 1;
1638             operands[i].imm.is_signed = ZYAN_FALSE;
1639             operands[i].imm.is_relative = ZYAN_FALSE;
1640             break;
1641         default:
1642             break;
1643         }
1644         if (operands[i].type)
1645         {
1646             goto FinalizeOperand;
1647         }
1648 
1649         operands[i].encoding = operand->op.encoding;
1650 
1651         // Register operands
1652         switch (operand->type)
1653         {
1654         case ZYDIS_SEMANTIC_OPTYPE_GPR8:
1655             register_class = ZYDIS_REGCLASS_GPR8;
1656             break;
1657         case ZYDIS_SEMANTIC_OPTYPE_GPR16:
1658             register_class = ZYDIS_REGCLASS_GPR16;
1659             break;
1660         case ZYDIS_SEMANTIC_OPTYPE_GPR32:
1661             register_class = ZYDIS_REGCLASS_GPR32;
1662             break;
1663         case ZYDIS_SEMANTIC_OPTYPE_GPR64:
1664             register_class = ZYDIS_REGCLASS_GPR64;
1665             break;
1666         case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_64:
1667             ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
1668                 (instruction->operand_width == 64));
1669             register_class =
1670                 (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR16 : (
1671                     (instruction->operand_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
1672             break;
1673         case ZYDIS_SEMANTIC_OPTYPE_GPR32_32_64:
1674             ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
1675                 (instruction->operand_width == 64));
1676             register_class =
1677                 (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR32 : (
1678                     (instruction->operand_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
1679             break;
1680         case ZYDIS_SEMANTIC_OPTYPE_GPR16_32_32:
1681             ZYAN_ASSERT((instruction->operand_width == 16) || (instruction->operand_width == 32) ||
1682                 (instruction->operand_width == 64));
1683             register_class =
1684                 (instruction->operand_width == 16) ? ZYDIS_REGCLASS_GPR16 : ZYDIS_REGCLASS_GPR32;
1685             break;
1686         case ZYDIS_SEMANTIC_OPTYPE_GPR_ASZ:
1687             ZYAN_ASSERT((instruction->address_width == 16) || (instruction->address_width == 32) ||
1688                 (instruction->address_width == 64));
1689             register_class =
1690                 (instruction->address_width == 16) ? ZYDIS_REGCLASS_GPR16 : (
1691                     (instruction->address_width == 32) ? ZYDIS_REGCLASS_GPR32 : ZYDIS_REGCLASS_GPR64);
1692             break;
1693         case ZYDIS_SEMANTIC_OPTYPE_FPR:
1694             register_class = ZYDIS_REGCLASS_X87;
1695             break;
1696         case ZYDIS_SEMANTIC_OPTYPE_MMX:
1697             register_class = ZYDIS_REGCLASS_MMX;
1698             break;
1699         case ZYDIS_SEMANTIC_OPTYPE_XMM:
1700             register_class = ZYDIS_REGCLASS_XMM;
1701             break;
1702         case ZYDIS_SEMANTIC_OPTYPE_YMM:
1703             register_class = ZYDIS_REGCLASS_YMM;
1704             break;
1705         case ZYDIS_SEMANTIC_OPTYPE_ZMM:
1706             register_class = ZYDIS_REGCLASS_ZMM;
1707             break;
1708         case ZYDIS_SEMANTIC_OPTYPE_TMM:
1709             register_class = ZYDIS_REGCLASS_TMM;
1710             break;
1711         case ZYDIS_SEMANTIC_OPTYPE_BND:
1712             register_class = ZYDIS_REGCLASS_BOUND;
1713             break;
1714         case ZYDIS_SEMANTIC_OPTYPE_SREG:
1715             register_class = ZYDIS_REGCLASS_SEGMENT;
1716             break;
1717         case ZYDIS_SEMANTIC_OPTYPE_CR:
1718             register_class = ZYDIS_REGCLASS_CONTROL;
1719             break;
1720         case ZYDIS_SEMANTIC_OPTYPE_DR:
1721             register_class = ZYDIS_REGCLASS_DEBUG;
1722             break;
1723         case ZYDIS_SEMANTIC_OPTYPE_MASK:
1724             register_class = ZYDIS_REGCLASS_MASK;
1725             break;
1726         default:
1727             break;
1728         }
1729         if (register_class)
1730         {
1731             switch (operand->op.encoding)
1732             {
1733             case ZYDIS_OPERAND_ENCODING_MODRM_REG:
1734                 ZYAN_CHECK(
1735                     ZydisDecodeOperandRegister(
1736                         instruction, &operands[i], register_class,
1737                         ZydisCalcRegisterId(
1738                             context, instruction, ZYDIS_REG_ENCODING_REG, register_class)));
1739                 break;
1740             case ZYDIS_OPERAND_ENCODING_MODRM_RM:
1741                 ZYAN_CHECK(
1742                     ZydisDecodeOperandRegister(
1743                         instruction, &operands[i], register_class,
1744                         ZydisCalcRegisterId(
1745                             context, instruction, ZYDIS_REG_ENCODING_RM, register_class)));
1746                 break;
1747             case ZYDIS_OPERAND_ENCODING_OPCODE:
1748                 ZYAN_CHECK(
1749                     ZydisDecodeOperandRegister(
1750                         instruction, &operands[i], register_class,
1751                         ZydisCalcRegisterId(
1752                             context, instruction, ZYDIS_REG_ENCODING_OPCODE, register_class)));
1753                 break;
1754             case ZYDIS_OPERAND_ENCODING_NDSNDD:
1755                 ZYAN_CHECK(
1756                     ZydisDecodeOperandRegister(
1757                         instruction, &operands[i], register_class,
1758                         ZydisCalcRegisterId(
1759                             context, instruction, ZYDIS_REG_ENCODING_NDSNDD, register_class)));
1760                 break;
1761             case ZYDIS_OPERAND_ENCODING_MASK:
1762                 ZYAN_CHECK(
1763                     ZydisDecodeOperandRegister(
1764                         instruction, &operands[i], register_class,
1765                         ZydisCalcRegisterId(
1766                             context, instruction, ZYDIS_REG_ENCODING_MASK, register_class)));
1767                 break;
1768             case ZYDIS_OPERAND_ENCODING_IS4:
1769                 ZYAN_CHECK(
1770                     ZydisDecodeOperandRegister(
1771                         instruction, &operands[i], register_class,
1772                         ZydisCalcRegisterId(
1773                             context, instruction, ZYDIS_REG_ENCODING_IS4, register_class)));
1774                 break;
1775             default:
1776                 ZYAN_UNREACHABLE;
1777             }
1778 
1779             if (operand->is_multisource4)
1780             {
1781                 operands[i].attributes |= ZYDIS_OATTRIB_IS_MULTISOURCE4;
1782             }
1783 
1784             goto FinalizeOperand;
1785         }
1786 
1787         // Memory operands
1788         switch (operand->type)
1789         {
1790         case ZYDIS_SEMANTIC_OPTYPE_MEM:
1791             ZYAN_CHECK(
1792                 ZydisDecodeOperandMemory(
1793                     context, instruction, &operands[i], ZYDIS_REGCLASS_INVALID));
1794             break;
1795         case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBX:
1796             ZYAN_CHECK(
1797                 ZydisDecodeOperandMemory(
1798                     context, instruction, &operands[i], ZYDIS_REGCLASS_XMM));
1799             operands[i].mem.type = ZYDIS_MEMOP_TYPE_VSIB;
1800             break;
1801         case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBY:
1802             ZYAN_CHECK(
1803                 ZydisDecodeOperandMemory(
1804                     context, instruction, &operands[i], ZYDIS_REGCLASS_YMM));
1805             operands[i].mem.type = ZYDIS_MEMOP_TYPE_VSIB;
1806             break;
1807         case ZYDIS_SEMANTIC_OPTYPE_MEM_VSIBZ:
1808             ZYAN_CHECK(
1809                 ZydisDecodeOperandMemory(
1810                     context, instruction, &operands[i], ZYDIS_REGCLASS_ZMM));
1811             operands[i].mem.type = ZYDIS_MEMOP_TYPE_VSIB;
1812             break;
1813         case ZYDIS_SEMANTIC_OPTYPE_PTR:
1814             ZYAN_ASSERT((instruction->raw.imm[0].size == 16) ||
1815                 (instruction->raw.imm[0].size == 32));
1816             ZYAN_ASSERT(instruction->raw.imm[1].size == 16);
1817             operands[i].type = ZYDIS_OPERAND_TYPE_POINTER;
1818             operands[i].ptr.offset = (ZyanU32)instruction->raw.imm[0].value.u;
1819             operands[i].ptr.segment = (ZyanU16)instruction->raw.imm[1].value.u;
1820             break;
1821         case ZYDIS_SEMANTIC_OPTYPE_AGEN:
1822             operands[i].actions = 0; // TODO: Remove after generator update
1823             ZYAN_CHECK(
1824                 ZydisDecodeOperandMemory(
1825                     context, instruction, &operands[i], ZYDIS_REGCLASS_INVALID));
1826             operands[i].mem.type = ZYDIS_MEMOP_TYPE_AGEN;
1827             break;
1828         case ZYDIS_SEMANTIC_OPTYPE_MOFFS:
1829             ZYAN_ASSERT(instruction->raw.disp.size);
1830             operands[i].type = ZYDIS_OPERAND_TYPE_MEMORY;
1831             operands[i].mem.type = ZYDIS_MEMOP_TYPE_MEM;
1832             operands[i].mem.disp.has_displacement = ZYAN_TRUE;
1833             operands[i].mem.disp.value = instruction->raw.disp.value;
1834             break;
1835         case ZYDIS_SEMANTIC_OPTYPE_MIB:
1836             operands[i].actions = 0; // TODO: Remove after generator update
1837             ZYAN_CHECK(
1838                 ZydisDecodeOperandMemory(
1839                     context, instruction, &operands[i], ZYDIS_REGCLASS_INVALID));
1840             operands[i].mem.type = ZYDIS_MEMOP_TYPE_MIB;
1841             break;
1842         default:
1843             break;
1844         }
1845         if (operands[i].type)
1846         {
1847 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
1848             // Handle compressed 8-bit displacement
1849             if (((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
1850                 (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX)) &&
1851                 (instruction->raw.disp.size == 8))
1852             {
1853                 operands[i].mem.disp.value *= context->cd8_scale;
1854             }
1855 #endif
1856 
1857             goto FinalizeOperand;
1858         }
1859 
1860         // Immediate operands
1861         switch (operand->type)
1862         {
1863         case ZYDIS_SEMANTIC_OPTYPE_REL:
1864             ZYAN_ASSERT(instruction->raw.imm[imm_id].is_relative);
1865             ZYAN_FALLTHROUGH;
1866         case ZYDIS_SEMANTIC_OPTYPE_IMM:
1867             ZYAN_ASSERT((imm_id == 0) || (imm_id == 1));
1868             operands[i].type = ZYDIS_OPERAND_TYPE_IMMEDIATE;
1869             operands[i].size = operand->size[context->eosz_index] * 8;
1870             if (operand->op.encoding == ZYDIS_OPERAND_ENCODING_IS4)
1871             {
1872                 // The upper half of the 8-bit immediate is used to encode a register specifier
1873                 ZYAN_ASSERT(instruction->raw.imm[imm_id].size == 8);
1874                 operands[i].imm.value.u = (ZyanU8)instruction->raw.imm[imm_id].value.u & 0x0F;
1875             }
1876             else
1877             {
1878                 operands[i].imm.value.u = instruction->raw.imm[imm_id].value.u;
1879             }
1880             operands[i].imm.is_signed = instruction->raw.imm[imm_id].is_signed;
1881             operands[i].imm.is_relative = instruction->raw.imm[imm_id].is_relative;
1882             ++imm_id;
1883             break;
1884         default:
1885             break;
1886         }
1887         ZYAN_ASSERT(operands[i].type == ZYDIS_OPERAND_TYPE_IMMEDIATE);
1888 
1889     FinalizeOperand:
1890         // Set segment-register for memory operands
1891         if (operands[i].type == ZYDIS_OPERAND_TYPE_MEMORY)
1892         {
1893             if (!operand->ignore_seg_override &&
1894                 instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_CS)
1895             {
1896                 operands[i].mem.segment = ZYDIS_REGISTER_CS;
1897             }
1898             else
1899                 if (!operand->ignore_seg_override &&
1900                     instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_SS)
1901                 {
1902                     operands[i].mem.segment = ZYDIS_REGISTER_SS;
1903                 }
1904                 else
1905                     if (!operand->ignore_seg_override &&
1906                         instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_DS)
1907                     {
1908                         operands[i].mem.segment = ZYDIS_REGISTER_DS;
1909                     }
1910                     else
1911                         if (!operand->ignore_seg_override &&
1912                             instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_ES)
1913                         {
1914                             operands[i].mem.segment = ZYDIS_REGISTER_ES;
1915                         }
1916                         else
1917                             if (!operand->ignore_seg_override &&
1918                                 instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_FS)
1919                             {
1920                                 operands[i].mem.segment = ZYDIS_REGISTER_FS;
1921                             }
1922                             else
1923                                 if (!operand->ignore_seg_override &&
1924                                     instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT_GS)
1925                                 {
1926                                     operands[i].mem.segment = ZYDIS_REGISTER_GS;
1927                                 }
1928                                 else
1929                                 {
1930                                     if (operands[i].mem.segment == ZYDIS_REGISTER_NONE)
1931                                     {
1932                                         if ((operands[i].mem.base == ZYDIS_REGISTER_RSP) ||
1933                                             (operands[i].mem.base == ZYDIS_REGISTER_RBP) ||
1934                                             (operands[i].mem.base == ZYDIS_REGISTER_ESP) ||
1935                                             (operands[i].mem.base == ZYDIS_REGISTER_EBP) ||
1936                                             (operands[i].mem.base == ZYDIS_REGISTER_SP) ||
1937                                             (operands[i].mem.base == ZYDIS_REGISTER_BP))
1938                                         {
1939                                             operands[i].mem.segment = ZYDIS_REGISTER_SS;
1940                                         }
1941                                         else
1942                                         {
1943                                             operands[i].mem.segment = ZYDIS_REGISTER_DS;
1944                                         }
1945                                     }
1946                                 }
1947         }
1948 
1949         ZydisSetOperandSizeAndElementInfo(context, instruction, &operands[i], operand);
1950         ++operand;
1951     }
1952 
1953 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
1954     // Fix operand-action for EVEX/MVEX instructions with merge-mask
1955     if (instruction->avx.mask.mode == ZYDIS_MASK_MODE_MERGING)
1956     {
1957         ZYAN_ASSERT(operand_count >= 1);
1958         switch (operands[0].actions)
1959         {
1960         case ZYDIS_OPERAND_ACTION_WRITE:
1961             if (operands[0].type == ZYDIS_OPERAND_TYPE_MEMORY)
1962             {
1963                 operands[0].actions = ZYDIS_OPERAND_ACTION_CONDWRITE;
1964             }
1965             else
1966             {
1967                 operands[0].actions = ZYDIS_OPERAND_ACTION_READ_CONDWRITE;
1968             }
1969             break;
1970         case ZYDIS_OPERAND_ACTION_READWRITE:
1971             operands[0].actions = ZYDIS_OPERAND_ACTION_READ_CONDWRITE;
1972             break;
1973         default:
1974             break;
1975         }
1976     }
1977 #endif
1978 
1979     return ZYAN_STATUS_SUCCESS;
1980 }
1981 #endif
1982 
1983 /* ---------------------------------------------------------------------------------------------- */
1984 
1985 #ifndef ZYDIS_MINIMAL_MODE
1986 /**
1987  * Sets attributes for the given instruction.
1988  *
1989  * @param   state       A pointer to the `ZydisDecoderState` struct.
1990  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
1991  * @param   definition  A pointer to the `ZydisInstructionDefinition` struct.
1992  */
1993 static void ZydisSetAttributes(ZydisDecoderState* state, ZydisDecodedInstruction* instruction,
1994     const ZydisInstructionDefinition* definition)
1995 {
1996     ZYAN_ASSERT(state);
1997     ZYAN_ASSERT(instruction);
1998     ZYAN_ASSERT(definition);
1999 
2000     if (definition->cpu_state != ZYDIS_RW_ACTION_NONE)
2001     {
2002         static const ZydisInstructionAttributes mapping[ZYDIS_RW_ACTION_MAX_VALUE + 1] =
2003         {
2004             /* NONE      */ 0,
2005             /* READ      */ ZYDIS_ATTRIB_CPU_STATE_CR,
2006             /* WRITE     */ ZYDIS_ATTRIB_CPU_STATE_CW,
2007             /* READWRITE */ ZYDIS_ATTRIB_CPU_STATE_CR | ZYDIS_ATTRIB_CPU_STATE_CW
2008         };
2009         ZYAN_ASSERT(definition->cpu_state < ZYAN_ARRAY_LENGTH(mapping));
2010         instruction->attributes |= mapping[definition->cpu_state];
2011     }
2012 
2013     if (definition->fpu_state != ZYDIS_RW_ACTION_NONE)
2014     {
2015         static const ZydisInstructionAttributes mapping[ZYDIS_RW_ACTION_MAX_VALUE + 1] =
2016         {
2017             /* NONE      */ 0,
2018             /* READ      */ ZYDIS_ATTRIB_FPU_STATE_CR,
2019             /* WRITE     */ ZYDIS_ATTRIB_FPU_STATE_CW,
2020             /* READWRITE */ ZYDIS_ATTRIB_FPU_STATE_CR | ZYDIS_ATTRIB_FPU_STATE_CW
2021         };
2022         ZYAN_ASSERT(definition->fpu_state < ZYAN_ARRAY_LENGTH(mapping));
2023         instruction->attributes |= mapping[definition->fpu_state];
2024     }
2025 
2026     if (definition->xmm_state != ZYDIS_RW_ACTION_NONE)
2027     {
2028         static const ZydisInstructionAttributes mapping[ZYDIS_RW_ACTION_MAX_VALUE + 1] =
2029         {
2030             /* NONE      */ 0,
2031             /* READ      */ ZYDIS_ATTRIB_XMM_STATE_CR,
2032             /* WRITE     */ ZYDIS_ATTRIB_XMM_STATE_CW,
2033             /* READWRITE */ ZYDIS_ATTRIB_XMM_STATE_CR | ZYDIS_ATTRIB_XMM_STATE_CW
2034         };
2035         ZYAN_ASSERT(definition->xmm_state < ZYAN_ARRAY_LENGTH(mapping));
2036         instruction->attributes |= mapping[definition->xmm_state];
2037     }
2038 
2039     switch (instruction->encoding)
2040     {
2041     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
2042     {
2043         const ZydisInstructionDefinitionLEGACY* def =
2044             (const ZydisInstructionDefinitionLEGACY*)definition;
2045 
2046         if (def->is_privileged)
2047         {
2048             instruction->attributes |= ZYDIS_ATTRIB_IS_PRIVILEGED;
2049         }
2050         if (def->accepts_LOCK)
2051         {
2052             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_LOCK;
2053             if (state->prefixes.has_lock)
2054             {
2055                 instruction->attributes |= ZYDIS_ATTRIB_HAS_LOCK;
2056                 instruction->raw.prefixes[state->prefixes.offset_lock].type =
2057                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2058             }
2059         }
2060         if (def->accepts_REP)
2061         {
2062             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_REP;
2063         }
2064         if (def->accepts_REPEREPZ)
2065         {
2066             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_REPE;
2067         }
2068         if (def->accepts_REPNEREPNZ)
2069         {
2070             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_REPNE;
2071         }
2072         if (def->accepts_BOUND)
2073         {
2074             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_BND;
2075         }
2076         if (def->accepts_XACQUIRE)
2077         {
2078             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_XACQUIRE;
2079         }
2080         if (def->accepts_XRELEASE)
2081         {
2082             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_XRELEASE;
2083         }
2084         if (def->accepts_hle_without_lock)
2085         {
2086             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_HLE_WITHOUT_LOCK;
2087         }
2088 
2089         switch (state->prefixes.group1)
2090         {
2091         case 0xF2:
2092             if (instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_REPNE)
2093             {
2094                 instruction->attributes |= ZYDIS_ATTRIB_HAS_REPNE;
2095                 break;
2096             }
2097             if (instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_XACQUIRE)
2098             {
2099                 if ((instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK) ||
2100                     (def->accepts_hle_without_lock))
2101                 {
2102                     instruction->attributes |= ZYDIS_ATTRIB_HAS_XACQUIRE;
2103                     break;
2104                 }
2105             }
2106             if ((state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_MPX)) &&
2107                 instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_BND)
2108             {
2109                 instruction->attributes |= ZYDIS_ATTRIB_HAS_BND;
2110                 break;
2111             }
2112             break;
2113         case 0xF3:
2114             if (instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_REP)
2115             {
2116                 instruction->attributes |= ZYDIS_ATTRIB_HAS_REP;
2117                 break;
2118             }
2119             if (instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_REPE)
2120             {
2121                 instruction->attributes |= ZYDIS_ATTRIB_HAS_REPE;
2122                 break;
2123             }
2124             if (instruction->attributes & ZYDIS_ATTRIB_ACCEPTS_XRELEASE)
2125             {
2126                 if ((instruction->attributes & ZYDIS_ATTRIB_HAS_LOCK) ||
2127                     (def->accepts_hle_without_lock))
2128                 {
2129                     instruction->attributes |= ZYDIS_ATTRIB_HAS_XRELEASE;
2130                     break;
2131                 }
2132             }
2133             break;
2134         default:
2135             break;
2136         }
2137         if ((instruction->raw.prefixes[state->prefixes.offset_group1].type ==
2138              ZYDIS_PREFIX_TYPE_IGNORED) &&
2139             (instruction->attributes & (
2140              ZYDIS_ATTRIB_HAS_REP | ZYDIS_ATTRIB_HAS_REPE | ZYDIS_ATTRIB_HAS_REPNE |
2141              ZYDIS_ATTRIB_HAS_BND | ZYDIS_ATTRIB_HAS_XACQUIRE | ZYDIS_ATTRIB_HAS_XRELEASE)))
2142         {
2143             instruction->raw.prefixes[state->prefixes.offset_group1].type =
2144                 ZYDIS_PREFIX_TYPE_EFFECTIVE;
2145         }
2146 
2147         if (def->accepts_branch_hints)
2148         {
2149             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_BRANCH_HINTS;
2150             switch (state->prefixes.group2)
2151             {
2152             case 0x2E:
2153                 instruction->attributes |= ZYDIS_ATTRIB_HAS_BRANCH_NOT_TAKEN;
2154                 instruction->raw.prefixes[state->prefixes.offset_group2].type =
2155                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2156                 break;
2157             case 0x3E:
2158                 instruction->attributes |= ZYDIS_ATTRIB_HAS_BRANCH_TAKEN;
2159                 instruction->raw.prefixes[state->prefixes.offset_group2].type =
2160                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2161                 break;
2162             default:
2163                 break;
2164             }
2165         }
2166 
2167         if (def->accepts_NOTRACK)
2168         {
2169             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_NOTRACK;
2170             if ((state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_CET)) &&
2171                 (state->prefixes.offset_notrack >= 0))
2172             {
2173                 instruction->attributes |= ZYDIS_ATTRIB_HAS_NOTRACK;
2174                 instruction->raw.prefixes[state->prefixes.offset_notrack].type =
2175                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2176             }
2177         }
2178 
2179         if (def->accepts_segment && !def->accepts_branch_hints)
2180         {
2181             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_SEGMENT;
2182             if (state->prefixes.effective_segment &&
2183                 !(instruction->attributes & ZYDIS_ATTRIB_HAS_NOTRACK))
2184             {
2185                 switch (state->prefixes.effective_segment)
2186                 {
2187                 case 0x2E:
2188                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS;
2189                     break;
2190                 case 0x36:
2191                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS;
2192                     break;
2193                 case 0x3E:
2194                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_DS;
2195                     break;
2196                 case 0x26:
2197                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES;
2198                     break;
2199                 case 0x64:
2200                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_FS;
2201                     break;
2202                 case 0x65:
2203                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_GS;
2204                     break;
2205                 default:
2206                     ZYAN_UNREACHABLE;
2207                 }
2208             }
2209             if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT)
2210             {
2211                 instruction->raw.prefixes[state->prefixes.offset_segment].type =
2212                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2213             }
2214         }
2215 
2216         break;
2217     }
2218     case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
2219     case ZYDIS_INSTRUCTION_ENCODING_XOP:
2220     case ZYDIS_INSTRUCTION_ENCODING_VEX:
2221     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
2222     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
2223         if (definition->accepts_segment)
2224         {
2225             instruction->attributes |= ZYDIS_ATTRIB_ACCEPTS_SEGMENT;
2226             if (state->prefixes.effective_segment)
2227             {
2228                 switch (state->prefixes.effective_segment)
2229                 {
2230                 case 0x2E:
2231                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_CS;
2232                     break;
2233                 case 0x36:
2234                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_SS;
2235                     break;
2236                 case 0x3E:
2237                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_DS;
2238                     break;
2239                 case 0x26:
2240                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_ES;
2241                     break;
2242                 case 0x64:
2243                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_FS;
2244                     break;
2245                 case 0x65:
2246                     instruction->attributes |= ZYDIS_ATTRIB_HAS_SEGMENT_GS;
2247                     break;
2248                 default:
2249                     ZYAN_UNREACHABLE;
2250                 }
2251             }
2252             if (instruction->attributes & ZYDIS_ATTRIB_HAS_SEGMENT)
2253             {
2254                 instruction->raw.prefixes[state->prefixes.offset_segment].type =
2255                     ZYDIS_PREFIX_TYPE_EFFECTIVE;
2256             }
2257         }
2258         break;
2259     default:
2260         ZYAN_UNREACHABLE;
2261     }
2262 }
2263 #endif
2264 
2265 #ifndef ZYDIS_MINIMAL_MODE
2266 /**
2267  * Sets AVX-specific information for the given instruction.
2268  *
2269  * @param   context     A pointer to the `ZydisDecoderContext` struct.
2270  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
2271  * @param   definition  A pointer to the `ZydisInstructionDefinition` struct.
2272  *
2273  * Information set for `XOP`:
2274  * - Vector Length
2275  *
2276  * Information set for `VEX`:
2277  * - Vector length
2278  * - Static broadcast-factor
2279  *
2280  * Information set for `EVEX`:
2281  * - Vector length
2282  * - Broadcast-factor (static and dynamic)
2283  * - Rounding-mode and SAE
2284  * - Mask mode
2285  * - Compressed 8-bit displacement scale-factor
2286  *
2287  * Information set for `MVEX`:
2288  * - Vector length
2289  * - Broadcast-factor (static and dynamic)
2290  * - Rounding-mode and SAE
2291  * - Swizzle- and conversion-mode
2292  * - Mask mode
2293  * - Eviction hint
2294  * - Compressed 8-bit displacement scale-factor
2295  */
2296 static void ZydisSetAVXInformation(ZydisDecoderContext* context,
2297     ZydisDecodedInstruction* instruction, const ZydisInstructionDefinition* definition)
2298 {
2299     ZYAN_ASSERT(context);
2300     ZYAN_ASSERT(instruction);
2301     ZYAN_ASSERT(definition);
2302 
2303     switch (instruction->encoding)
2304     {
2305     case ZYDIS_INSTRUCTION_ENCODING_XOP:
2306     {
2307         // Vector length
2308         static const ZyanU16 lookup[2] =
2309         {
2310             128,
2311             256
2312         };
2313         ZYAN_ASSERT(context->vector_unified.LL < ZYAN_ARRAY_LENGTH(lookup));
2314         instruction->avx.vector_length = lookup[context->vector_unified.LL];
2315         break;
2316     }
2317     case ZYDIS_INSTRUCTION_ENCODING_VEX:
2318     {
2319         // Vector length
2320         static const ZyanU16 lookup[2] =
2321         {
2322             128,
2323             256
2324         };
2325         ZYAN_ASSERT(context->vector_unified.LL < ZYAN_ARRAY_LENGTH(lookup));
2326         instruction->avx.vector_length = lookup[context->vector_unified.LL];
2327 
2328         // Static broadcast-factor
2329         const ZydisInstructionDefinitionVEX* def =
2330             (const ZydisInstructionDefinitionVEX*)definition;
2331         if (def->broadcast)
2332         {
2333             instruction->avx.broadcast.is_static = ZYAN_TRUE;
2334             static ZydisBroadcastMode broadcasts[ZYDIS_VEX_STATIC_BROADCAST_MAX_VALUE + 1] =
2335             {
2336                 ZYDIS_BROADCAST_MODE_INVALID,
2337                 ZYDIS_BROADCAST_MODE_1_TO_2,
2338                 ZYDIS_BROADCAST_MODE_1_TO_4,
2339                 ZYDIS_BROADCAST_MODE_1_TO_8,
2340                 ZYDIS_BROADCAST_MODE_1_TO_16,
2341                 ZYDIS_BROADCAST_MODE_1_TO_32,
2342                 ZYDIS_BROADCAST_MODE_2_TO_4
2343             };
2344             instruction->avx.broadcast.mode = broadcasts[def->broadcast];
2345         }
2346         break;
2347     }
2348     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
2349     {
2350 #ifndef ZYDIS_DISABLE_AVX512
2351         const ZydisInstructionDefinitionEVEX* def =
2352             (const ZydisInstructionDefinitionEVEX*)definition;
2353 
2354         // Vector length
2355         ZyanU8 vector_length = context->vector_unified.LL;
2356         if (def->vector_length)
2357         {
2358             vector_length = def->vector_length - 1;
2359         }
2360         static const ZyanU16 lookup[3] =
2361         {
2362             128,
2363             256,
2364             512
2365         };
2366         ZYAN_ASSERT(vector_length < ZYAN_ARRAY_LENGTH(lookup));
2367         instruction->avx.vector_length = lookup[vector_length];
2368 
2369         context->evex.tuple_type = def->tuple_type;
2370         if (def->tuple_type)
2371         {
2372             ZYAN_ASSERT(instruction->raw.modrm.mod != 3);
2373             ZYAN_ASSERT(def->element_size);
2374 
2375             // Element size
2376             static const ZyanU8 element_sizes[ZYDIS_IELEMENT_SIZE_MAX_VALUE + 1] =
2377             {
2378                   0,   8,  16,  32,  64, 128
2379             };
2380             ZYAN_ASSERT(def->element_size < ZYAN_ARRAY_LENGTH(element_sizes));
2381             context->evex.element_size = element_sizes[def->element_size];
2382 
2383             // Compressed disp8 scale and broadcast-factor
2384             switch (def->tuple_type)
2385             {
2386             case ZYDIS_TUPLETYPE_FV:
2387             {
2388                 const ZyanU8 evex_b = instruction->raw.evex.b;
2389                 ZYAN_ASSERT(evex_b < 2);
2390                 ZYAN_ASSERT(!evex_b || ((!context->vector_unified.W && (context->evex.element_size == 16 ||
2391                                                                         context->evex.element_size == 32)) ||
2392                                         ( context->vector_unified.W &&  context->evex.element_size == 64)));
2393                 ZYAN_ASSERT(!evex_b || def->functionality == ZYDIS_EVEX_FUNC_BC);
2394 
2395                 static const ZyanU8 scales[2][3][3] =
2396                 {
2397                     /*B0*/ { /*16*/ { 16, 32, 64 }, /*32*/ { 16, 32, 64 }, /*64*/ { 16, 32, 64 } },
2398                     /*B1*/ { /*16*/ {  2,  2,  2 }, /*32*/ {  4,  4,  4 }, /*64*/ {  8,  8,  8 } }
2399                 };
2400                 static const ZydisBroadcastMode broadcasts[2][3][3] =
2401                 {
2402                     /*B0*/
2403                     {
2404                         /*16*/
2405                         {
2406                             ZYDIS_BROADCAST_MODE_INVALID,
2407                             ZYDIS_BROADCAST_MODE_INVALID,
2408                             ZYDIS_BROADCAST_MODE_INVALID
2409                         },
2410                         /*32*/
2411                         {
2412                             ZYDIS_BROADCAST_MODE_INVALID,
2413                             ZYDIS_BROADCAST_MODE_INVALID,
2414                             ZYDIS_BROADCAST_MODE_INVALID
2415                         },
2416                         /*64*/
2417                         {
2418                             ZYDIS_BROADCAST_MODE_INVALID,
2419                             ZYDIS_BROADCAST_MODE_INVALID,
2420                             ZYDIS_BROADCAST_MODE_INVALID
2421                         }
2422                     },
2423                     /*B1*/
2424                     {
2425                         /*16*/
2426                         {
2427                             ZYDIS_BROADCAST_MODE_1_TO_8,
2428                             ZYDIS_BROADCAST_MODE_1_TO_16,
2429                             ZYDIS_BROADCAST_MODE_1_TO_32
2430                         },
2431                         /*32*/
2432                         {
2433                             ZYDIS_BROADCAST_MODE_1_TO_4,
2434                             ZYDIS_BROADCAST_MODE_1_TO_8,
2435                             ZYDIS_BROADCAST_MODE_1_TO_16
2436                         },
2437                         /*64*/
2438                         {
2439                             ZYDIS_BROADCAST_MODE_1_TO_2,
2440                             ZYDIS_BROADCAST_MODE_1_TO_4,
2441                             ZYDIS_BROADCAST_MODE_1_TO_8
2442                         }
2443                     }
2444                 };
2445 
2446                 const ZyanU8 size_index = context->evex.element_size >> 5;
2447                 ZYAN_ASSERT(size_index < 3);
2448 
2449                 context->cd8_scale = scales[evex_b][size_index][vector_length];
2450                 instruction->avx.broadcast.mode = broadcasts[evex_b][size_index][vector_length];
2451                 break;
2452             }
2453             case ZYDIS_TUPLETYPE_HV:
2454             {
2455                 const ZyanU8 evex_b = instruction->raw.evex.b;
2456                 ZYAN_ASSERT(evex_b < 2);
2457                 ZYAN_ASSERT(!context->vector_unified.W);
2458                 ZYAN_ASSERT((context->evex.element_size == 16) ||
2459                             (context->evex.element_size == 32));
2460                 ZYAN_ASSERT(!evex_b || def->functionality == ZYDIS_EVEX_FUNC_BC);
2461 
2462                 static const ZyanU8 scales[2][2][3] =
2463                 {
2464                     /*B0*/ { /*16*/ {  8, 16, 32 }, /*32*/ {  8, 16, 32 } },
2465                     /*B1*/ { /*16*/ {  2,  2,  2 }, /*32*/ {  4,  4,  4 } }
2466                 };
2467                 static const ZydisBroadcastMode broadcasts[2][2][3] =
2468                 {
2469                     /*B0*/
2470                     {
2471                         /*16*/
2472                         {
2473                             ZYDIS_BROADCAST_MODE_INVALID,
2474                             ZYDIS_BROADCAST_MODE_INVALID,
2475                             ZYDIS_BROADCAST_MODE_INVALID
2476                         },
2477                         /*32*/
2478                         {
2479                             ZYDIS_BROADCAST_MODE_INVALID,
2480                             ZYDIS_BROADCAST_MODE_INVALID,
2481                             ZYDIS_BROADCAST_MODE_INVALID
2482                         }
2483                     },
2484                     /*B1*/
2485                     {
2486                         /*16*/
2487                         {
2488                             ZYDIS_BROADCAST_MODE_1_TO_4,
2489                             ZYDIS_BROADCAST_MODE_1_TO_8,
2490                             ZYDIS_BROADCAST_MODE_1_TO_16
2491                         },
2492                         /*32*/
2493                         {
2494                             ZYDIS_BROADCAST_MODE_1_TO_2,
2495                             ZYDIS_BROADCAST_MODE_1_TO_4,
2496                             ZYDIS_BROADCAST_MODE_1_TO_8
2497                         }
2498                     }
2499                 };
2500 
2501                 const ZyanU8 size_index = context->evex.element_size >> 5;
2502                 ZYAN_ASSERT(size_index < 3);
2503 
2504                 context->cd8_scale = scales[evex_b][size_index][vector_length];
2505                 instruction->avx.broadcast.mode = broadcasts[evex_b][size_index][vector_length];
2506                 break;
2507             }
2508             case ZYDIS_TUPLETYPE_FVM:
2509             {
2510                 static const ZyanU8 scales[3] =
2511                 {
2512                     16, 32, 64
2513                 };
2514                 context->cd8_scale = scales[vector_length];
2515                 break;
2516             }
2517             case ZYDIS_TUPLETYPE_GSCAT:
2518                 switch (context->vector_unified.W)
2519                 {
2520                 case 0:
2521                     ZYAN_ASSERT(context->evex.element_size == 32);
2522                     break;
2523                 case 1:
2524                     ZYAN_ASSERT(context->evex.element_size == 64);
2525                     break;
2526                 default:
2527                     ZYAN_UNREACHABLE;
2528                 }
2529                 ZYAN_FALLTHROUGH;
2530             case ZYDIS_TUPLETYPE_T1S:
2531             {
2532                 static const ZyanU8 scales[6] =
2533                 {
2534                     /*   */  0,
2535                     /*  8*/  1,
2536                     /* 16*/  2,
2537                     /* 32*/  4,
2538                     /* 64*/  8,
2539                     /*128*/ 16,
2540                 };
2541                 ZYAN_ASSERT(def->element_size < ZYAN_ARRAY_LENGTH(scales));
2542                 context->cd8_scale = scales[def->element_size];
2543                 break;
2544             };
2545             case ZYDIS_TUPLETYPE_T1F:
2546             {
2547                 static const ZyanU8 scales[3] =
2548                 {
2549                     /* 16*/ 2,
2550                     /* 32*/ 4,
2551                     /* 64*/ 8
2552                 };
2553 
2554                 const ZyanU8 size_index = context->evex.element_size >> 5;
2555                 ZYAN_ASSERT(size_index < 3);
2556 
2557                 context->cd8_scale = scales[size_index];
2558                 break;
2559             }
2560             case ZYDIS_TUPLETYPE_T1_4X:
2561                 ZYAN_ASSERT(context->evex.element_size == 32);
2562                 ZYAN_ASSERT(context->vector_unified.W == 0);
2563                 context->cd8_scale = 16;
2564                 break;
2565             case ZYDIS_TUPLETYPE_T2:
2566                 switch (context->vector_unified.W)
2567                 {
2568                 case 0:
2569                     ZYAN_ASSERT(context->evex.element_size == 32);
2570                     context->cd8_scale = 8;
2571                     break;
2572                 case 1:
2573                     ZYAN_ASSERT(context->evex.element_size == 64);
2574                     ZYAN_ASSERT((instruction->avx.vector_length == 256) ||
2575                                 (instruction->avx.vector_length == 512));
2576                     context->cd8_scale = 16;
2577                     break;
2578                 default:
2579                     ZYAN_UNREACHABLE;
2580                 }
2581                 break;
2582             case ZYDIS_TUPLETYPE_T4:
2583                 switch (context->vector_unified.W)
2584                 {
2585                 case 0:
2586                     ZYAN_ASSERT(context->evex.element_size == 32);
2587                     ZYAN_ASSERT((instruction->avx.vector_length == 256) ||
2588                                 (instruction->avx.vector_length == 512));
2589                     context->cd8_scale = 16;
2590                     break;
2591                 case 1:
2592                     ZYAN_ASSERT(context->evex.element_size == 64);
2593                     ZYAN_ASSERT(instruction->avx.vector_length == 512);
2594                     context->cd8_scale = 32;
2595                     break;
2596                 default:
2597                     ZYAN_UNREACHABLE;
2598                 }
2599                 break;
2600             case ZYDIS_TUPLETYPE_T8:
2601                 ZYAN_ASSERT(!context->vector_unified.W);
2602                 ZYAN_ASSERT(instruction->avx.vector_length == 512);
2603                 ZYAN_ASSERT(context->evex.element_size == 32);
2604                 context->cd8_scale = 32;
2605                 break;
2606             case ZYDIS_TUPLETYPE_HVM:
2607             {
2608                 static const ZyanU8 scales[3] =
2609                 {
2610                      8, 16, 32
2611                 };
2612                 context->cd8_scale = scales[vector_length];
2613                 break;
2614             }
2615             case ZYDIS_TUPLETYPE_QVM:
2616             {
2617                 static const ZyanU8 scales[3] =
2618                 {
2619                      4,  8, 16
2620                 };
2621                 context->cd8_scale = scales[vector_length];
2622                 break;
2623             }
2624             case ZYDIS_TUPLETYPE_OVM:
2625             {
2626                 static const ZyanU8 scales[3] =
2627                 {
2628                      2,  4,  8
2629                 };
2630                 context->cd8_scale = scales[vector_length];
2631                 break;
2632             }
2633             case ZYDIS_TUPLETYPE_M128:
2634                 context->cd8_scale = 16;
2635                 break;
2636             case ZYDIS_TUPLETYPE_DUP:
2637             {
2638                 static const ZyanU8 scales[3] =
2639                 {
2640                      8, 32, 64
2641                 };
2642                 context->cd8_scale = scales[vector_length];
2643                 break;
2644             }
2645             case ZYDIS_TUPLETYPE_QUARTER:
2646             {
2647                 const ZyanU8 evex_b = instruction->raw.evex.b;
2648                 ZYAN_ASSERT(evex_b < 2);
2649                 ZYAN_ASSERT(!context->vector_unified.W);
2650                 ZYAN_ASSERT(context->evex.element_size == 16);
2651                 ZYAN_ASSERT(!evex_b || def->functionality == ZYDIS_EVEX_FUNC_BC);
2652 
2653                 static const ZyanU8 scales[2][3] =
2654                 {
2655                     /*B0*/ {  4,  8, 16 },
2656                     /*B1*/ {  2,  2,  2 }
2657                 };
2658                 static const ZydisBroadcastMode broadcasts[2][3] =
2659                 {
2660                     /*B0*/
2661                     {
2662                         ZYDIS_BROADCAST_MODE_INVALID,
2663                         ZYDIS_BROADCAST_MODE_INVALID,
2664                         ZYDIS_BROADCAST_MODE_INVALID
2665                     },
2666                     /*B1*/
2667                     {
2668                         ZYDIS_BROADCAST_MODE_1_TO_2,
2669                         ZYDIS_BROADCAST_MODE_1_TO_4,
2670                         ZYDIS_BROADCAST_MODE_1_TO_8
2671                     }
2672                 };
2673                 context->cd8_scale = scales[evex_b][vector_length];
2674                 instruction->avx.broadcast.mode = broadcasts[evex_b][vector_length];
2675                 break;
2676             }
2677             default:
2678                 ZYAN_UNREACHABLE;
2679             }
2680         } else
2681         {
2682             ZYAN_ASSERT(instruction->raw.modrm.mod == 3);
2683         }
2684 
2685         // Static broadcast-factor
2686         if (def->broadcast)
2687         {
2688             ZYAN_ASSERT(!instruction->avx.broadcast.mode);
2689             instruction->avx.broadcast.is_static = ZYAN_TRUE;
2690             static const ZydisBroadcastMode broadcasts[ZYDIS_EVEX_STATIC_BROADCAST_MAX_VALUE + 1] =
2691             {
2692                 ZYDIS_BROADCAST_MODE_INVALID,
2693                 ZYDIS_BROADCAST_MODE_1_TO_2,
2694                 ZYDIS_BROADCAST_MODE_1_TO_4,
2695                 ZYDIS_BROADCAST_MODE_1_TO_8,
2696                 ZYDIS_BROADCAST_MODE_1_TO_16,
2697                 ZYDIS_BROADCAST_MODE_1_TO_32,
2698                 ZYDIS_BROADCAST_MODE_1_TO_64,
2699                 ZYDIS_BROADCAST_MODE_2_TO_4,
2700                 ZYDIS_BROADCAST_MODE_2_TO_8,
2701                 ZYDIS_BROADCAST_MODE_2_TO_16,
2702                 ZYDIS_BROADCAST_MODE_4_TO_8,
2703                 ZYDIS_BROADCAST_MODE_4_TO_16,
2704                 ZYDIS_BROADCAST_MODE_8_TO_16
2705             };
2706             ZYAN_ASSERT(def->broadcast < ZYAN_ARRAY_LENGTH(broadcasts));
2707             instruction->avx.broadcast.mode = broadcasts[def->broadcast];
2708         }
2709 
2710         // Rounding mode and SAE
2711         if (instruction->raw.evex.b)
2712         {
2713             switch (def->functionality)
2714             {
2715             case ZYDIS_EVEX_FUNC_INVALID:
2716             case ZYDIS_EVEX_FUNC_BC:
2717                 // Noting to do here
2718                 break;
2719             case ZYDIS_EVEX_FUNC_RC:
2720                 instruction->avx.rounding.mode = ZYDIS_ROUNDING_MODE_RN + context->vector_unified.LL;
2721                 ZYAN_FALLTHROUGH;
2722             case ZYDIS_EVEX_FUNC_SAE:
2723                 instruction->avx.has_sae = ZYAN_TRUE;
2724                 break;
2725             default:
2726                 ZYAN_UNREACHABLE;
2727             }
2728         }
2729 
2730         // Mask
2731         instruction->avx.mask.reg = ZYDIS_REGISTER_K0 + instruction->raw.evex.aaa;
2732         switch (def->mask_override)
2733         {
2734         case ZYDIS_MASK_OVERRIDE_DEFAULT:
2735             instruction->avx.mask.mode = ZYDIS_MASK_MODE_MERGING + instruction->raw.evex.z;
2736             break;
2737         case ZYDIS_MASK_OVERRIDE_ZEROING:
2738             instruction->avx.mask.mode = ZYDIS_MASK_MODE_ZEROING;
2739             break;
2740         case ZYDIS_MASK_OVERRIDE_CONTROL:
2741             instruction->avx.mask.mode = ZYDIS_MASK_MODE_CONTROL + instruction->raw.evex.z;
2742             break;
2743         default:
2744             ZYAN_UNREACHABLE;
2745         }
2746         if (!instruction->raw.evex.aaa)
2747         {
2748             instruction->avx.mask.mode = ZYDIS_MASK_MODE_DISABLED;
2749         }
2750 #else
2751         ZYAN_UNREACHABLE;
2752 #endif
2753         break;
2754     }
2755     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
2756     {
2757 #ifndef ZYDIS_DISABLE_KNC
2758         // Vector length
2759         instruction->avx.vector_length = 512;
2760 
2761         const ZydisInstructionDefinitionMVEX* def =
2762             (const ZydisInstructionDefinitionMVEX*)definition;
2763 
2764         // Static broadcast-factor
2765         ZyanU8 index = def->has_element_granularity;
2766         ZYAN_ASSERT(!index || !def->broadcast);
2767         if (!index && def->broadcast)
2768         {
2769             instruction->avx.broadcast.is_static = ZYAN_TRUE;
2770             switch (def->broadcast)
2771             {
2772             case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_8:
2773                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_1_TO_8;
2774                 index = 1;
2775                 break;
2776             case ZYDIS_MVEX_STATIC_BROADCAST_1_TO_16:
2777                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_1_TO_16;
2778                 index = 1;
2779                 break;
2780             case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_8:
2781                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_4_TO_8;
2782                 index = 2;
2783                 break;
2784             case ZYDIS_MVEX_STATIC_BROADCAST_4_TO_16:
2785                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_4_TO_16;
2786                 index = 2;
2787                 break;
2788             default:
2789                 ZYAN_UNREACHABLE;
2790             }
2791         }
2792 
2793         // Compressed disp8 scale and broadcast-factor
2794         switch (def->functionality)
2795         {
2796         case ZYDIS_MVEX_FUNC_IGNORED:
2797         case ZYDIS_MVEX_FUNC_INVALID:
2798         case ZYDIS_MVEX_FUNC_RC:
2799         case ZYDIS_MVEX_FUNC_SAE:
2800         case ZYDIS_MVEX_FUNC_SWIZZLE_32:
2801         case ZYDIS_MVEX_FUNC_SWIZZLE_64:
2802             // Nothing to do here
2803             break;
2804         case ZYDIS_MVEX_FUNC_F_32:
2805         case ZYDIS_MVEX_FUNC_I_32:
2806         case ZYDIS_MVEX_FUNC_F_64:
2807         case ZYDIS_MVEX_FUNC_I_64:
2808             context->cd8_scale = 64;
2809             break;
2810         case ZYDIS_MVEX_FUNC_SF_32:
2811         case ZYDIS_MVEX_FUNC_SF_32_BCST:
2812         case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
2813         case ZYDIS_MVEX_FUNC_UF_32:
2814         {
2815             static const ZyanU8 lookup[3][8] =
2816             {
2817                 { 64,  4, 16, 32, 16, 16, 32, 32 },
2818                 {  4,  0,  0,  2,  1,  1,  2,  2 },
2819                 { 16,  0,  0,  8,  4,  4,  8,  8 }
2820             };
2821             ZYAN_ASSERT(instruction->raw.mvex.SSS < ZYAN_ARRAY_LENGTH(lookup[index]));
2822             context->cd8_scale = lookup[index][instruction->raw.mvex.SSS];
2823             break;
2824         }
2825         case ZYDIS_MVEX_FUNC_SI_32:
2826         case ZYDIS_MVEX_FUNC_UI_32:
2827         case ZYDIS_MVEX_FUNC_SI_32_BCST:
2828         case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
2829         {
2830             static const ZyanU8 lookup[3][8] =
2831             {
2832                 { 64,  4, 16,  0, 16, 16, 32, 32 },
2833                 {  4,  0,  0,  0,  1,  1,  2,  2 },
2834                 { 16,  0,  0,  0,  4,  4,  8,  8 }
2835             };
2836             ZYAN_ASSERT(instruction->raw.mvex.SSS < ZYAN_ARRAY_LENGTH(lookup[index]));
2837             context->cd8_scale = lookup[index][instruction->raw.mvex.SSS];
2838             break;
2839         }
2840         case ZYDIS_MVEX_FUNC_SF_64:
2841         case ZYDIS_MVEX_FUNC_UF_64:
2842         case ZYDIS_MVEX_FUNC_SI_64:
2843         case ZYDIS_MVEX_FUNC_UI_64:
2844         {
2845             static const ZyanU8 lookup[3][3] =
2846             {
2847                 { 64,  8, 32 },
2848                 {  8,  0,  0 },
2849                 { 32,  0,  0 }
2850             };
2851             ZYAN_ASSERT(instruction->raw.mvex.SSS < ZYAN_ARRAY_LENGTH(lookup[index]));
2852             context->cd8_scale = lookup[index][instruction->raw.mvex.SSS];
2853             break;
2854         }
2855         case ZYDIS_MVEX_FUNC_DF_32:
2856         case ZYDIS_MVEX_FUNC_DI_32:
2857         {
2858             static const ZyanU8 lookup[2][8] =
2859             {
2860                 { 64,  0,  0, 32, 16, 16, 32, 32 },
2861                 {  4,  0,  0,  2,  1,  1,  2,  2 }
2862             };
2863             ZYAN_ASSERT(index < 2);
2864             ZYAN_ASSERT(instruction->raw.mvex.SSS < ZYAN_ARRAY_LENGTH(lookup[index]));
2865             context->cd8_scale = lookup[index][instruction->raw.mvex.SSS];
2866             break;
2867         }
2868         case ZYDIS_MVEX_FUNC_DF_64:
2869         case ZYDIS_MVEX_FUNC_DI_64:
2870         {
2871             static const ZyanU8 lookup[2][1] =
2872             {
2873                 { 64 },
2874                 {  8 }
2875             };
2876             ZYAN_ASSERT(index < 2);
2877             ZYAN_ASSERT(instruction->raw.mvex.SSS < ZYAN_ARRAY_LENGTH(lookup[index]));
2878             context->cd8_scale = lookup[index][instruction->raw.mvex.SSS];
2879             break;
2880         }
2881         default:
2882             ZYAN_UNREACHABLE;
2883         }
2884 
2885         // Rounding mode, sae, swizzle, convert
2886         context->mvex.functionality = def->functionality;
2887         switch (def->functionality)
2888         {
2889         case ZYDIS_MVEX_FUNC_IGNORED:
2890         case ZYDIS_MVEX_FUNC_INVALID:
2891         case ZYDIS_MVEX_FUNC_F_32:
2892         case ZYDIS_MVEX_FUNC_I_32:
2893         case ZYDIS_MVEX_FUNC_F_64:
2894         case ZYDIS_MVEX_FUNC_I_64:
2895             // Nothing to do here
2896             break;
2897         case ZYDIS_MVEX_FUNC_RC:
2898             instruction->avx.rounding.mode = ZYDIS_ROUNDING_MODE_RN + (instruction->raw.mvex.SSS & 3);
2899             ZYAN_FALLTHROUGH;
2900         case ZYDIS_MVEX_FUNC_SAE:
2901             if (instruction->raw.mvex.SSS >= 4)
2902             {
2903                 instruction->avx.has_sae = ZYAN_TRUE;
2904             }
2905             break;
2906         case ZYDIS_MVEX_FUNC_SWIZZLE_32:
2907         case ZYDIS_MVEX_FUNC_SWIZZLE_64:
2908             instruction->avx.swizzle.mode = ZYDIS_SWIZZLE_MODE_DCBA + instruction->raw.mvex.SSS;
2909             break;
2910         case ZYDIS_MVEX_FUNC_SF_32:
2911         case ZYDIS_MVEX_FUNC_SF_32_BCST:
2912         case ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16:
2913             switch (instruction->raw.mvex.SSS)
2914             {
2915             case 0:
2916                 break;
2917             case 1:
2918                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_1_TO_16;
2919                 break;
2920             case 2:
2921                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_4_TO_16;
2922                 break;
2923             case 3:
2924                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_FLOAT16;
2925                 break;
2926             case 4:
2927                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT8;
2928                 break;
2929             case 5:
2930                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT8;
2931                 break;
2932             case 6:
2933                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT16;
2934                 break;
2935             case 7:
2936                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT16;
2937                 break;
2938             default:
2939                 ZYAN_UNREACHABLE;
2940             }
2941             break;
2942         case ZYDIS_MVEX_FUNC_SI_32:
2943         case ZYDIS_MVEX_FUNC_SI_32_BCST:
2944         case ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16:
2945             switch (instruction->raw.mvex.SSS)
2946             {
2947             case 0:
2948                 break;
2949             case 1:
2950                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_1_TO_16;
2951                 break;
2952             case 2:
2953                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_4_TO_16;
2954                 break;
2955             case 4:
2956                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT8;
2957                 break;
2958             case 5:
2959                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT8;
2960                 break;
2961             case 6:
2962                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT16;
2963                 break;
2964             case 7:
2965                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT16;
2966                 break;
2967             default:
2968                 ZYAN_UNREACHABLE;
2969             }
2970             break;
2971         case ZYDIS_MVEX_FUNC_SF_64:
2972         case ZYDIS_MVEX_FUNC_SI_64:
2973             switch (instruction->raw.mvex.SSS)
2974             {
2975             case 0:
2976                 break;
2977             case 1:
2978                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_1_TO_8;
2979                 break;
2980             case 2:
2981                 instruction->avx.broadcast.mode = ZYDIS_BROADCAST_MODE_4_TO_8;
2982                 break;
2983             default:
2984                 ZYAN_UNREACHABLE;
2985             }
2986             break;
2987         case ZYDIS_MVEX_FUNC_UF_32:
2988         case ZYDIS_MVEX_FUNC_DF_32:
2989             switch (instruction->raw.mvex.SSS)
2990             {
2991             case 0:
2992                 break;
2993             case 3:
2994                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_FLOAT16;
2995                 break;
2996             case 4:
2997                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT8;
2998                 break;
2999             case 5:
3000                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT8;
3001                 break;
3002             case 6:
3003                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT16;
3004                 break;
3005             case 7:
3006                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT16;
3007                 break;
3008             default:
3009                 ZYAN_UNREACHABLE;
3010             }
3011             break;
3012         case ZYDIS_MVEX_FUNC_UF_64:
3013         case ZYDIS_MVEX_FUNC_DF_64:
3014             break;
3015         case ZYDIS_MVEX_FUNC_UI_32:
3016         case ZYDIS_MVEX_FUNC_DI_32:
3017             switch (instruction->raw.mvex.SSS)
3018             {
3019             case 0:
3020                 break;
3021             case 4:
3022                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT8;
3023                 break;
3024             case 5:
3025                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT8;
3026                 break;
3027             case 6:
3028                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_UINT16;
3029                 break;
3030             case 7:
3031                 instruction->avx.conversion.mode = ZYDIS_CONVERSION_MODE_SINT16;
3032                 break;
3033             default:
3034                 ZYAN_UNREACHABLE;
3035             }
3036             break;
3037         case ZYDIS_MVEX_FUNC_UI_64:
3038         case ZYDIS_MVEX_FUNC_DI_64:
3039             break;
3040         default:
3041             ZYAN_UNREACHABLE;
3042         }
3043 
3044         // Eviction hint
3045         if ((instruction->raw.modrm.mod != 3) && instruction->raw.mvex.E)
3046         {
3047             instruction->avx.has_eviction_hint = ZYAN_TRUE;
3048         }
3049 
3050         // Mask
3051         instruction->avx.mask.mode = ZYDIS_MASK_MODE_MERGING;
3052         instruction->avx.mask.reg = ZYDIS_REGISTER_K0 + instruction->raw.mvex.kkk;
3053 #else
3054         ZYAN_UNREACHABLE;
3055 #endif
3056         break;
3057     }
3058     default:
3059         // Nothing to do here
3060         break;
3061     }
3062 }
3063 #endif
3064 
3065 /* ---------------------------------------------------------------------------------------------- */
3066 /* Physical instruction decoding                                                                  */
3067 /* ---------------------------------------------------------------------------------------------- */
3068 
3069 /**
3070  * Collects optional instruction prefixes.
3071  *
3072  * @param   state     A pointer to the `ZydisDecoderState` struct.
3073  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
3074  *
3075  * @return  A zyan status code.
3076  *
3077  * This function sets the corresponding flag for each prefix and automatically decodes the last
3078  * `REX`-prefix (if exists).
3079  */
3080 static ZyanStatus ZydisCollectOptionalPrefixes(ZydisDecoderState* state,
3081     ZydisDecodedInstruction* instruction)
3082 {
3083     ZYAN_ASSERT(state);
3084     ZYAN_ASSERT(instruction);
3085     ZYAN_ASSERT(instruction->raw.prefix_count == 0);
3086 
3087     ZyanU8 rex = 0x00;
3088     ZyanU8 offset = 0;
3089     ZyanBool done = ZYAN_FALSE;
3090     do
3091     {
3092         ZyanU8 prefix_byte;
3093         ZYAN_CHECK(ZydisInputPeek(state, instruction, &prefix_byte));
3094         switch (prefix_byte)
3095         {
3096         case 0xF0:
3097             state->prefixes.has_lock = ZYAN_TRUE;
3098             state->prefixes.offset_lock = offset;
3099             break;
3100         case 0xF2:
3101             ZYAN_FALLTHROUGH;
3102         case 0xF3:
3103             state->prefixes.group1 = prefix_byte;
3104             state->prefixes.mandatory_candidate = prefix_byte;
3105             state->prefixes.offset_group1 = offset;
3106             state->prefixes.offset_mandatory = offset;
3107             break;
3108         case 0x2E:
3109             ZYAN_FALLTHROUGH;
3110         case 0x36:
3111             ZYAN_FALLTHROUGH;
3112         case 0x3E:
3113             ZYAN_FALLTHROUGH;
3114         case 0x26:
3115             if (state->decoder->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
3116             {
3117                 if ((prefix_byte == 0x3E) &&
3118                     (state->prefixes.effective_segment != 0x64) &&
3119                     (state->prefixes.effective_segment != 0x65))
3120                 {
3121                     state->prefixes.offset_notrack = offset;
3122                 }
3123                 state->prefixes.group2 = prefix_byte;
3124                 state->prefixes.offset_group2 = offset;
3125                 break;
3126             }
3127             ZYAN_FALLTHROUGH;
3128         case 0x64:
3129             ZYAN_FALLTHROUGH;
3130         case 0x65:
3131             state->prefixes.group2 = prefix_byte;
3132             state->prefixes.offset_group2 = offset;
3133             state->prefixes.effective_segment = prefix_byte;
3134             state->prefixes.offset_segment = offset;
3135             state->prefixes.offset_notrack = -1;
3136             break;
3137         case 0x66:
3138             // context->prefixes.has_osz_override = ZYAN_TRUE;
3139             state->prefixes.offset_osz_override = offset;
3140             if (!state->prefixes.mandatory_candidate)
3141             {
3142                 state->prefixes.mandatory_candidate = 0x66;
3143                 state->prefixes.offset_mandatory = offset;
3144             }
3145             instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
3146             break;
3147         case 0x67:
3148             // context->prefixes.has_asz_override = ZYAN_TRUE;
3149             state->prefixes.offset_asz_override = offset;
3150             instruction->attributes |= ZYDIS_ATTRIB_HAS_ADDRESSSIZE;
3151             break;
3152         default:
3153             if ((state->decoder->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
3154                 (prefix_byte & 0xF0) == 0x40)
3155             {
3156                 rex = prefix_byte;
3157                 instruction->raw.rex.offset = offset;
3158             } else
3159             {
3160                 done = ZYAN_TRUE;
3161             }
3162             break;
3163         }
3164         if (!done)
3165         {
3166             // Invalidate `REX`, if it's not the last legacy prefix
3167             if (rex && (rex != prefix_byte))
3168             {
3169                 rex = 0x00;
3170                 instruction->raw.rex.offset = 0;
3171             }
3172             instruction->raw.prefixes[instruction->raw.prefix_count++].value = prefix_byte;
3173             ZydisInputSkip(state, instruction);
3174             ++offset;
3175         }
3176     } while (!done);
3177 
3178     if (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
3179     {
3180         instruction->raw.prefixes[state->prefixes.offset_osz_override].type =
3181             ZYDIS_PREFIX_TYPE_EFFECTIVE;
3182     }
3183     if (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE)
3184     {
3185         instruction->raw.prefixes[state->prefixes.offset_asz_override].type =
3186             ZYDIS_PREFIX_TYPE_EFFECTIVE;
3187     }
3188     if (rex)
3189     {
3190         instruction->raw.prefixes[instruction->raw.rex.offset].type = ZYDIS_PREFIX_TYPE_EFFECTIVE;
3191         ZydisDecodeREX(state->context, instruction, rex);
3192     }
3193     if ((state->decoder->machine_mode != ZYDIS_MACHINE_MODE_LONG_64) &&
3194         (state->prefixes.group2 == 0x3E))
3195     {
3196         state->prefixes.offset_notrack = state->prefixes.offset_group2;
3197     }
3198 
3199     return ZYAN_STATUS_SUCCESS;
3200 }
3201 
3202 /**
3203  * Decodes optional instruction parts like the ModRM byte, the SIB byte and
3204  * additional displacements and/or immediate values.
3205  *
3206  * @param   state       A pointer to the `ZydisDecoderState` struct.
3207  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
3208  * @param   info        A pointer to the `ZydisInstructionEncodingInfo` struct.
3209  *
3210  * @return  A zyan status code.
3211  */
3212 static ZyanStatus ZydisDecodeOptionalInstructionParts(ZydisDecoderState* state,
3213     ZydisDecodedInstruction* instruction, const ZydisInstructionEncodingInfo* info)
3214 {
3215     ZYAN_ASSERT(state);
3216     ZYAN_ASSERT(instruction);
3217     ZYAN_ASSERT(info);
3218 
3219     ZydisDecoderContext* context = state->context;
3220 
3221     if (info->flags & ZYDIS_INSTR_ENC_FLAG_HAS_MODRM)
3222     {
3223         if (!instruction->raw.modrm.offset)
3224         {
3225             instruction->raw.modrm.offset = instruction->length;
3226             ZyanU8 modrm_byte;
3227             ZYAN_CHECK(ZydisInputNext(state, instruction, &modrm_byte));
3228             ZydisDecodeModRM(instruction, modrm_byte);
3229         }
3230 
3231         if (!(info->flags & ZYDIS_INSTR_ENC_FLAG_FORCE_REG_FORM))
3232         {
3233             ZyanU8 has_sib = 0;
3234             ZyanU8 displacement_size = 0;
3235             switch (instruction->address_width)
3236             {
3237             case 16:
3238                 switch (instruction->raw.modrm.mod)
3239                 {
3240                 case 0:
3241                     if (instruction->raw.modrm.rm == 6)
3242                     {
3243                         displacement_size = 16;
3244                     }
3245                     break;
3246                 case 1:
3247                     displacement_size = 8;
3248                     break;
3249                 case 2:
3250                     displacement_size = 16;
3251                     break;
3252                 case 3:
3253                     break;
3254                 default:
3255                     ZYAN_UNREACHABLE;
3256                 }
3257                 break;
3258             case 32:
3259             case 64:
3260                 has_sib =
3261                     (instruction->raw.modrm.mod != 3) && (instruction->raw.modrm.rm == 4);
3262                 switch (instruction->raw.modrm.mod)
3263                 {
3264                 case 0:
3265                     if (instruction->raw.modrm.rm == 5)
3266                     {
3267                         if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
3268                         {
3269                             instruction->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
3270                         }
3271                         displacement_size = 32;
3272                     }
3273                     break;
3274                 case 1:
3275                     displacement_size = 8;
3276                     break;
3277                 case 2:
3278                     displacement_size = 32;
3279                     break;
3280                 case 3:
3281                     break;
3282                 default:
3283                     ZYAN_UNREACHABLE;
3284                 }
3285                 break;
3286             default:
3287                 ZYAN_UNREACHABLE;
3288             }
3289             if (has_sib)
3290             {
3291                 instruction->raw.sib.offset = instruction->length;
3292                 ZyanU8 sib_byte;
3293                 ZYAN_CHECK(ZydisInputNext(state, instruction, &sib_byte));
3294                 ZydisDecodeSIB(instruction, sib_byte);
3295                 if (instruction->raw.sib.base == 5)
3296                 {
3297                     displacement_size = (instruction->raw.modrm.mod == 1) ? 8 : 32;
3298                 }
3299             }
3300             if (displacement_size)
3301             {
3302                 ZYAN_CHECK(ZydisReadDisplacement(state, instruction, displacement_size));
3303             }
3304         }
3305 
3306         context->reg_info.is_mod_reg = (instruction->raw.modrm.mod == 3) ||
3307                                        (info->flags & ZYDIS_INSTR_ENC_FLAG_FORCE_REG_FORM);
3308     }
3309 
3310     if (info->flags & ZYDIS_INSTR_ENC_FLAG_HAS_DISP)
3311     {
3312         ZYAN_CHECK(ZydisReadDisplacement(
3313             state, instruction, info->disp.size[context->easz_index]));
3314     }
3315 
3316     if (info->flags & ZYDIS_INSTR_ENC_FLAG_HAS_IMM0)
3317     {
3318         if (info->imm[0].is_relative)
3319         {
3320             instruction->attributes |= ZYDIS_ATTRIB_IS_RELATIVE;
3321         }
3322         ZYAN_CHECK(ZydisReadImmediate(state, instruction, 0,
3323             info->imm[0].size[context->eosz_index], info->imm[0].is_signed,
3324             info->imm[0].is_relative));
3325     }
3326 
3327     if (info->flags & ZYDIS_INSTR_ENC_FLAG_HAS_IMM1)
3328     {
3329         ZYAN_ASSERT(!(info->flags & ZYDIS_INSTR_ENC_FLAG_HAS_DISP));
3330         ZYAN_CHECK(ZydisReadImmediate(state, instruction, 1,
3331             info->imm[1].size[context->eosz_index], info->imm[1].is_signed,
3332             info->imm[1].is_relative));
3333     }
3334 
3335     return ZYAN_STATUS_SUCCESS;
3336 }
3337 
3338 /* ---------------------------------------------------------------------------------------------- */
3339 
3340 /**
3341  * Sets the effective operand size for the given instruction.
3342  *
3343  * @param   context     A pointer to the `ZydisDecoderContext` struct
3344  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
3345  * @param   definition  A pointer to the `ZydisInstructionDefinition` struct.
3346  */
3347 static void ZydisSetEffectiveOperandWidth(ZydisDecoderContext* context,
3348     ZydisDecodedInstruction* instruction, const ZydisInstructionDefinition* definition)
3349 {
3350     ZYAN_ASSERT(context);
3351     ZYAN_ASSERT(instruction);
3352     ZYAN_ASSERT(definition);
3353 
3354     static const ZyanU8 operand_size_map[8][8] =
3355     {
3356         // Default for most instructions
3357         {
3358             16, // 16 __ W0
3359             32, // 16 66 W0
3360             32, // 32 __ W0
3361             16, // 32 66 W0
3362             32, // 64 __ W0
3363             16, // 64 66 W0
3364             64, // 64 __ W1
3365             64  // 64 66 W1
3366         },
3367         // Operand size is forced to 8-bit (this is done later to preserve the `eosz_index`)
3368         {
3369             16, // 16 __ W0
3370             32, // 16 66 W0
3371             32, // 32 __ W0
3372             16, // 32 66 W0
3373             32, // 64 __ W0
3374             16, // 64 66 W0
3375             64, // 64 __ W1
3376             64  // 64 66 W1
3377         },
3378         // Operand size override 0x66 is ignored
3379         {
3380             16, // 16 __ W0
3381             16, // 16 66 W0
3382             32, // 32 __ W0
3383             32, // 32 66 W0
3384             32, // 64 __ W0
3385             32, // 64 66 W0
3386             64, // 64 __ W1
3387             64  // 64 66 W1
3388         },
3389         // REX.W promotes to 32-bit instead of 64-bit
3390         {
3391             16, // 16 __ W0
3392             32, // 16 66 W0
3393             32, // 32 __ W0
3394             16, // 32 66 W0
3395             32, // 64 __ W0
3396             16, // 64 66 W0
3397             32, // 64 __ W1
3398             32  // 64 66 W1
3399         },
3400         // Operand size defaults to 64-bit in 64-bit mode
3401         {
3402             16, // 16 __ W0
3403             32, // 16 66 W0
3404             32, // 32 __ W0
3405             16, // 32 66 W0
3406             64, // 64 __ W0
3407             16, // 64 66 W0
3408             64, // 64 __ W1
3409             64  // 64 66 W1
3410         },
3411         // Operand size is forced to 64-bit in 64-bit mode
3412         {
3413             16, // 16 __ W0
3414             32, // 16 66 W0
3415             32, // 32 __ W0
3416             16, // 32 66 W0
3417             64, // 64 __ W0
3418             64, // 64 66 W0
3419             64, // 64 __ W1
3420             64  // 64 66 W1
3421         },
3422         // Operand size is forced to 32-bit, if no REX.W is present.
3423         {
3424             32, // 16 __ W0
3425             32, // 16 66 W0
3426             32, // 32 __ W0
3427             32, // 32 66 W0
3428             32, // 64 __ W0
3429             32, // 64 66 W0
3430             64, // 64 __ W1
3431             64  // 64 66 W1
3432         },
3433         // Operand size is forced to 64-bit in 64-bit mode and forced to 32-bit in all other modes.
3434         // This is used for e.g. `mov CR, GPR` and `mov GPR, CR`.
3435         {
3436             32, // 16 __ W0
3437             32, // 16 66 W0
3438             32, // 32 __ W0
3439             32, // 32 66 W0
3440             64, // 64 __ W0
3441             64, // 64 66 W0
3442             64, // 64 __ W1
3443             64  // 64 66 W1
3444         }
3445     };
3446 
3447     ZyanU8 index = (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) ? 1 : 0;
3448     if ((instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_32) ||
3449         (instruction->machine_mode == ZYDIS_MACHINE_MODE_LEGACY_32))
3450     {
3451         index += 2;
3452     }
3453     else if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
3454     {
3455         index += 4;
3456         index += (context->vector_unified.W & 0x01) << 1;
3457     }
3458 
3459     ZYAN_ASSERT(definition->operand_size_map < ZYAN_ARRAY_LENGTH(operand_size_map));
3460     ZYAN_ASSERT(index < ZYAN_ARRAY_LENGTH(operand_size_map[definition->operand_size_map]));
3461 
3462     instruction->operand_width = operand_size_map[definition->operand_size_map][index];
3463     context->eosz_index = instruction->operand_width >> 5;
3464 
3465     // TODO: Cleanup code and remove hardcoded condition
3466     if (definition->operand_size_map == 1)
3467     {
3468         instruction->operand_width = 8;
3469     }
3470 }
3471 
3472 /**
3473  * Sets the effective address width for the given instruction.
3474  *
3475  * @param   context     A pointer to the `ZydisDecoderContext` struct.
3476  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
3477  * @param   definition  A pointer to the `ZydisInstructionDefinition` struct.
3478  */
3479 static void ZydisSetEffectiveAddressWidth(ZydisDecoderContext* context,
3480     ZydisDecodedInstruction* instruction, const ZydisInstructionDefinition* definition)
3481 {
3482     ZYAN_ASSERT(context);
3483     ZYAN_ASSERT(instruction);
3484 
3485     static const ZyanU8 address_size_map[3][8] =
3486     {
3487         // Default for most instructions
3488         {
3489             16, // 16 __
3490             32, // 16 67
3491             32, // 32 __
3492             16, // 32 67
3493             64, // 64 __
3494             32  // 64 67
3495         },
3496         // The address-size override is ignored
3497         {
3498             16, // 16 __
3499             16, // 16 67
3500             32, // 32 __
3501             32, // 32 67
3502             64, // 64 __
3503             64  // 64 67
3504         },
3505         // The address-size is forced to 64-bit in 64-bit mode and 32-bit in non 64-bit mode. This
3506         // is used by e.g. `ENCLS`, `ENCLV`, `ENCLU`.
3507         {
3508             32, // 16 __
3509             32, // 16 67
3510             32, // 32 __
3511             32, // 32 67
3512             64, // 64 __
3513             64  // 64 67
3514         }
3515     };
3516 
3517     ZyanU8 index = (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 1 : 0;
3518     if ((instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_32) ||
3519         (instruction->machine_mode == ZYDIS_MACHINE_MODE_LEGACY_32))
3520     {
3521         index += 2;
3522     }
3523     else if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
3524     {
3525         index += 4;
3526     }
3527 
3528     ZYAN_ASSERT(definition->address_size_map < ZYAN_ARRAY_LENGTH(address_size_map));
3529     ZYAN_ASSERT(index < ZYAN_ARRAY_LENGTH(address_size_map[definition->address_size_map]));
3530 
3531     instruction->address_width = address_size_map[definition->address_size_map][index];
3532     context->easz_index = instruction->address_width >> 5;
3533 }
3534 
3535 /* ---------------------------------------------------------------------------------------------- */
3536 
3537 static ZyanStatus ZydisNodeHandlerXOP(const ZydisDecodedInstruction* instruction, ZyanU16* index)
3538 {
3539     ZYAN_ASSERT(instruction);
3540     ZYAN_ASSERT(index);
3541 
3542     switch (instruction->encoding)
3543     {
3544     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
3545         *index = 0;
3546         break;
3547     case ZYDIS_INSTRUCTION_ENCODING_XOP:
3548         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_XOP);
3549         *index = (instruction->raw.xop.m_mmmm - 0x08) + (instruction->raw.xop.pp * 3) + 1;
3550         break;
3551     default:
3552         ZYAN_UNREACHABLE;
3553     }
3554     return ZYAN_STATUS_SUCCESS;
3555 }
3556 
3557 static ZyanStatus ZydisNodeHandlerVEX(const ZydisDecodedInstruction* instruction, ZyanU16* index)
3558 {
3559     ZYAN_ASSERT(instruction);
3560     ZYAN_ASSERT(index);
3561 
3562     switch (instruction->encoding)
3563     {
3564     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
3565         *index = 0;
3566         break;
3567     case ZYDIS_INSTRUCTION_ENCODING_VEX:
3568         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX);
3569         *index = instruction->raw.vex.m_mmmm + (instruction->raw.vex.pp << 2) + 1;
3570         break;
3571     default:
3572         ZYAN_UNREACHABLE;
3573     }
3574     return ZYAN_STATUS_SUCCESS;
3575 }
3576 
3577 static ZyanStatus ZydisNodeHandlerEMVEX(const ZydisDecodedInstruction* instruction, ZyanU16* index)
3578 {
3579     ZYAN_ASSERT(instruction);
3580     ZYAN_ASSERT(index);
3581 
3582     switch (instruction->encoding)
3583     {
3584     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
3585         *index = 0;
3586         break;
3587     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
3588         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX);
3589         *index = instruction->raw.evex.mmm + (instruction->raw.evex.pp << 3) + 1;
3590         break;
3591     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
3592         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX);
3593         *index = instruction->raw.mvex.mmmm + (instruction->raw.mvex.pp << 2) + 33;
3594         break;
3595     default:
3596         ZYAN_UNREACHABLE;
3597     }
3598     return ZYAN_STATUS_SUCCESS;
3599 }
3600 
3601 static ZyanStatus ZydisNodeHandlerOpcode(ZydisDecoderState* state,
3602     ZydisDecodedInstruction* instruction, ZyanU16* index)
3603 {
3604     ZYAN_ASSERT(state);
3605     ZYAN_ASSERT(instruction);
3606     ZYAN_ASSERT(index);
3607 
3608     // Handle possible encoding-prefix and opcode-map changes
3609     switch (instruction->encoding)
3610     {
3611     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
3612         ZYAN_CHECK(ZydisInputNext(state, instruction, &instruction->opcode));
3613         switch (instruction->opcode_map)
3614         {
3615         case ZYDIS_OPCODE_MAP_DEFAULT:
3616             switch (instruction->opcode)
3617             {
3618             case 0x0F:
3619                 instruction->opcode_map = ZYDIS_OPCODE_MAP_0F;
3620                 break;
3621             case 0xC4:
3622             case 0xC5:
3623             case 0x62:
3624             {
3625                 ZyanU8 next_input;
3626                 ZYAN_CHECK(ZydisInputPeek(state, instruction, &next_input));
3627                 if (((next_input & 0xF0) >= 0xC0) ||
3628                     (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64))
3629                 {
3630                     if (instruction->attributes & ZYDIS_ATTRIB_HAS_REX)
3631                     {
3632                         return ZYDIS_STATUS_ILLEGAL_REX;
3633                     }
3634                     if (state->prefixes.has_lock)
3635                     {
3636                         return ZYDIS_STATUS_ILLEGAL_LOCK;
3637                     }
3638                     if (state->prefixes.mandatory_candidate)
3639                     {
3640                         return ZYDIS_STATUS_ILLEGAL_LEGACY_PFX;
3641                     }
3642                     ZyanU8 prefix_bytes[4] = { 0, 0, 0, 0 };
3643                     prefix_bytes[0] = instruction->opcode;
3644                     switch (instruction->opcode)
3645                     {
3646                     case 0xC4:
3647                         instruction->raw.vex.offset = instruction->length - 1;
3648                         // Read additional 3-byte VEX-prefix data
3649                         ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX));
3650                         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, &prefix_bytes[1], 2));
3651                         break;
3652                     case 0xC5:
3653                         instruction->raw.vex.offset = instruction->length - 1;
3654                         // Read additional 2-byte VEX-prefix data
3655                         ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX));
3656                         ZYAN_CHECK(ZydisInputNext(state, instruction, &prefix_bytes[1]));
3657                         break;
3658                     case 0x62:
3659 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
3660                         // Read additional EVEX/MVEX-prefix data
3661                         ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX));
3662                         ZYAN_ASSERT(!(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX));
3663                         ZYAN_CHECK(ZydisInputNextBytes(state, instruction, &prefix_bytes[1], 3));
3664                         break;
3665 #else
3666                         return ZYDIS_STATUS_DECODING_ERROR;
3667 #endif
3668                     default:
3669                         ZYAN_UNREACHABLE;
3670                     }
3671                     switch (instruction->opcode)
3672                     {
3673                     case 0xC4:
3674                     case 0xC5:
3675                         // Decode VEX-prefix
3676                         instruction->encoding = ZYDIS_INSTRUCTION_ENCODING_VEX;
3677                         ZYAN_CHECK(ZydisDecodeVEX(state->context, instruction, prefix_bytes));
3678                         instruction->opcode_map =
3679                             ZYDIS_OPCODE_MAP_DEFAULT + instruction->raw.vex.m_mmmm;
3680                         break;
3681                     case 0x62:
3682 #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
3683                         return ZYDIS_STATUS_DECODING_ERROR;
3684 #else
3685                         switch ((prefix_bytes[2] >> 2) & 0x01)
3686                         {
3687                         case 0:
3688 #ifndef ZYDIS_DISABLE_KNC
3689                             instruction->raw.mvex.offset = instruction->length - 4;
3690                             // `KNC` instructions are only valid in 64-bit mode.
3691                             // This condition catches the `MVEX` encoded ones to save a bunch of
3692                             // `mode` filters in the data-tables.
3693                             // `KNC` instructions with `VEX` encoding still require a `mode` filter.
3694                             if (state->decoder->machine_mode != ZYDIS_MACHINE_MODE_LONG_64)
3695                             {
3696                                 return ZYDIS_STATUS_DECODING_ERROR;
3697                             }
3698                             // Decode MVEX-prefix
3699                             instruction->encoding = ZYDIS_INSTRUCTION_ENCODING_MVEX;
3700                             ZYAN_CHECK(ZydisDecodeMVEX(state->context, instruction, prefix_bytes));
3701                             instruction->opcode_map =
3702                                 ZYDIS_OPCODE_MAP_DEFAULT + instruction->raw.mvex.mmmm;
3703                             break;
3704 #else
3705                             return ZYDIS_STATUS_DECODING_ERROR;
3706 #endif
3707                         case 1:
3708 #ifndef ZYDIS_DISABLE_AVX512
3709                             instruction->raw.evex.offset = instruction->length - 4;
3710                             // Decode EVEX-prefix
3711                             instruction->encoding = ZYDIS_INSTRUCTION_ENCODING_EVEX;
3712                             ZYAN_CHECK(ZydisDecodeEVEX(state->context, instruction, prefix_bytes));
3713                             instruction->opcode_map =
3714                                 ZYDIS_OPCODE_MAP_DEFAULT + instruction->raw.evex.mmm;
3715                             break;
3716 #else
3717                             return ZYDIS_STATUS_DECODING_ERROR;
3718 #endif
3719                         default:
3720                             ZYAN_UNREACHABLE;
3721                         }
3722                         break;
3723 #endif
3724                     default:
3725                         ZYAN_UNREACHABLE;
3726                     }
3727                 }
3728                 break;
3729             }
3730             case 0x8F:
3731             {
3732                 ZyanU8 next_input;
3733                 ZYAN_CHECK(ZydisInputPeek(state, instruction, &next_input));
3734                 if ((next_input & 0x1F) >= 8)
3735                 {
3736                     if (instruction->attributes & ZYDIS_ATTRIB_HAS_REX)
3737                     {
3738                         return ZYDIS_STATUS_ILLEGAL_REX;
3739                     }
3740                     if (state->prefixes.has_lock)
3741                     {
3742                         return ZYDIS_STATUS_ILLEGAL_LOCK;
3743                     }
3744                     if (state->prefixes.mandatory_candidate)
3745                     {
3746                         return ZYDIS_STATUS_ILLEGAL_LEGACY_PFX;
3747                     }
3748                     instruction->raw.xop.offset = instruction->length - 1;
3749                     ZyanU8 prefixBytes[3] = { 0x8F, 0x00, 0x00 };
3750                     // Read additional xop-prefix data
3751                     ZYAN_CHECK(ZydisInputNextBytes(state, instruction, &prefixBytes[1], 2));
3752                     // Decode xop-prefix
3753                     instruction->encoding = ZYDIS_INSTRUCTION_ENCODING_XOP;
3754                     ZYAN_CHECK(ZydisDecodeXOP(state->context, instruction, prefixBytes));
3755                     instruction->opcode_map =
3756                         ZYDIS_OPCODE_MAP_XOP8 + instruction->raw.xop.m_mmmm - 0x08;
3757                 }
3758                 break;
3759             }
3760             default:
3761                 break;
3762             }
3763             break;
3764         case ZYDIS_OPCODE_MAP_0F:
3765             switch (instruction->opcode)
3766             {
3767             case 0x0F:
3768                 if (state->prefixes.has_lock)
3769                 {
3770                     return ZYDIS_STATUS_ILLEGAL_LOCK;
3771                 }
3772                 instruction->encoding = ZYDIS_INSTRUCTION_ENCODING_3DNOW;
3773                 instruction->opcode_map = ZYDIS_OPCODE_MAP_0F0F;
3774                 break;
3775             case 0x38:
3776                 instruction->opcode_map = ZYDIS_OPCODE_MAP_0F38;
3777                 break;
3778             case 0x3A:
3779                 instruction->opcode_map = ZYDIS_OPCODE_MAP_0F3A;
3780                 break;
3781             default:
3782                 break;
3783             }
3784             break;
3785         case ZYDIS_OPCODE_MAP_0F38:
3786         case ZYDIS_OPCODE_MAP_0F3A:
3787         case ZYDIS_OPCODE_MAP_XOP8:
3788         case ZYDIS_OPCODE_MAP_XOP9:
3789         case ZYDIS_OPCODE_MAP_XOPA:
3790             // Nothing to do here
3791             break;
3792         default:
3793             ZYAN_UNREACHABLE;
3794         }
3795         break;
3796     case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
3797         // All 3DNOW (0x0F 0x0F) instructions are using the same operand encoding. We just
3798         // decode a random (pi2fw) instruction and extract the actual opcode later.
3799         *index = 0x0C;
3800         return ZYAN_STATUS_SUCCESS;
3801     default:
3802         ZYAN_CHECK(ZydisInputNext(state, instruction, &instruction->opcode));
3803         break;
3804     }
3805 
3806     *index = instruction->opcode;
3807     return ZYAN_STATUS_SUCCESS;
3808 }
3809 
3810 static ZyanStatus ZydisNodeHandlerMode(const ZydisDecodedInstruction* instruction, ZyanU16* index)
3811 {
3812     ZYAN_ASSERT(instruction);
3813     ZYAN_ASSERT(index);
3814 
3815     switch (instruction->machine_mode)
3816     {
3817     case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
3818     case ZYDIS_MACHINE_MODE_LEGACY_16:
3819     case ZYDIS_MACHINE_MODE_REAL_16:
3820         *index = 0;
3821         break;
3822     case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
3823     case ZYDIS_MACHINE_MODE_LEGACY_32:
3824         *index = 1;
3825         break;
3826     case ZYDIS_MACHINE_MODE_LONG_64:
3827         *index = 2;
3828         break;
3829     default:
3830         ZYAN_UNREACHABLE;
3831     }
3832     return ZYAN_STATUS_SUCCESS;
3833 }
3834 
3835 static ZyanStatus ZydisNodeHandlerModeCompact(const ZydisDecodedInstruction* instruction,
3836     ZyanU16* index)
3837 {
3838     ZYAN_ASSERT(instruction);
3839     ZYAN_ASSERT(index);
3840 
3841     *index = (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) ? 0 : 1;
3842     return ZYAN_STATUS_SUCCESS;
3843 }
3844 
3845 static ZyanStatus ZydisNodeHandlerModrmMod(ZydisDecoderState* state,
3846     ZydisDecodedInstruction* instruction, ZyanU16* index)
3847 {
3848     ZYAN_ASSERT(state);
3849     ZYAN_ASSERT(instruction);
3850     ZYAN_ASSERT(index);
3851 
3852     if (!instruction->raw.modrm.offset)
3853     {
3854         instruction->raw.modrm.offset = instruction->length;
3855         ZyanU8 modrm_byte;
3856         ZYAN_CHECK(ZydisInputNext(state, instruction, &modrm_byte));
3857         ZydisDecodeModRM(instruction, modrm_byte);
3858     }
3859     *index = instruction->raw.modrm.mod;
3860     return ZYAN_STATUS_SUCCESS;
3861 }
3862 
3863 static ZyanStatus ZydisNodeHandlerModrmModCompact(ZydisDecoderState* state,
3864     ZydisDecodedInstruction* instruction, ZyanU16* index)
3865 {
3866     ZYAN_CHECK(ZydisNodeHandlerModrmMod(state, instruction, index));
3867     *index = (*index == 0x3) ? 0 : 1;
3868     return ZYAN_STATUS_SUCCESS;
3869 }
3870 
3871 static ZyanStatus ZydisNodeHandlerModrmReg(ZydisDecoderState* state,
3872     ZydisDecodedInstruction* instruction, ZyanU16* index)
3873 {
3874     ZYAN_ASSERT(state);
3875     ZYAN_ASSERT(instruction);
3876     ZYAN_ASSERT(index);
3877 
3878     if (!instruction->raw.modrm.offset)
3879     {
3880         instruction->raw.modrm.offset = instruction->length;
3881         ZyanU8 modrm_byte;
3882         ZYAN_CHECK(ZydisInputNext(state, instruction, &modrm_byte));
3883         ZydisDecodeModRM(instruction, modrm_byte);
3884     }
3885     *index = instruction->raw.modrm.reg;
3886     return ZYAN_STATUS_SUCCESS;
3887 }
3888 
3889 static ZyanStatus ZydisNodeHandlerModrmRm(ZydisDecoderState* state,
3890     ZydisDecodedInstruction* instruction, ZyanU16* index)
3891 {
3892     ZYAN_ASSERT(state);
3893     ZYAN_ASSERT(instruction);
3894     ZYAN_ASSERT(index);
3895 
3896     if (!instruction->raw.modrm.offset)
3897     {
3898         instruction->raw.modrm.offset = instruction->length;
3899         ZyanU8 modrm_byte;
3900         ZYAN_CHECK(ZydisInputNext(state, instruction, &modrm_byte));
3901         ZydisDecodeModRM(instruction, modrm_byte);
3902     }
3903     *index = instruction->raw.modrm.rm;
3904     return ZYAN_STATUS_SUCCESS;
3905 }
3906 
3907 static ZyanStatus ZydisNodeHandlerMandatoryPrefix(const ZydisDecoderState* state,
3908     ZydisDecodedInstruction* instruction, ZyanU16* index)
3909 {
3910     ZYAN_ASSERT(state);
3911     ZYAN_ASSERT(instruction);
3912     ZYAN_ASSERT(index);
3913 
3914     switch (state->prefixes.mandatory_candidate)
3915     {
3916     case 0x66:
3917         instruction->raw.prefixes[state->prefixes.offset_mandatory].type =
3918             ZYDIS_PREFIX_TYPE_MANDATORY;
3919         instruction->attributes &= ~ZYDIS_ATTRIB_HAS_OPERANDSIZE;
3920         *index = 2;
3921         break;
3922     case 0xF3:
3923         instruction->raw.prefixes[state->prefixes.offset_mandatory].type =
3924             ZYDIS_PREFIX_TYPE_MANDATORY;
3925         *index = 3;
3926         break;
3927     case 0xF2:
3928         instruction->raw.prefixes[state->prefixes.offset_mandatory].type =
3929             ZYDIS_PREFIX_TYPE_MANDATORY;
3930         *index = 4;
3931         break;
3932     default:
3933         *index = 1;
3934         break;
3935     }
3936     // TODO: Consume prefix and make sure it's available again, if we need to fallback
3937 
3938     return ZYAN_STATUS_SUCCESS;
3939 }
3940 
3941 static ZyanStatus ZydisNodeHandlerOperandSize(const ZydisDecoderState* state,
3942     ZydisDecodedInstruction* instruction, ZyanU16* index)
3943 {
3944     ZYAN_ASSERT(state);
3945     ZYAN_ASSERT(instruction);
3946     ZYAN_ASSERT(index);
3947 
3948     if ((instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
3949         (state->context->vector_unified.W))
3950     {
3951         *index = 2;
3952     } else
3953     {
3954         if (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE)
3955         {
3956             instruction->raw.prefixes[state->prefixes.offset_osz_override].type =
3957                 ZYDIS_PREFIX_TYPE_EFFECTIVE;
3958         }
3959         switch (instruction->machine_mode)
3960         {
3961         case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
3962         case ZYDIS_MACHINE_MODE_LEGACY_16:
3963         case ZYDIS_MACHINE_MODE_REAL_16:
3964             *index = (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) ? 1 : 0;
3965             break;
3966         case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
3967         case ZYDIS_MACHINE_MODE_LEGACY_32:
3968         case ZYDIS_MACHINE_MODE_LONG_64:
3969             *index = (instruction->attributes & ZYDIS_ATTRIB_HAS_OPERANDSIZE) ? 0 : 1;
3970             break;
3971         default:
3972             ZYAN_UNREACHABLE;
3973         }
3974     }
3975 
3976     return ZYAN_STATUS_SUCCESS;
3977 }
3978 
3979 static ZyanStatus ZydisNodeHandlerAddressSize(ZydisDecodedInstruction* instruction, ZyanU16* index)
3980 {
3981     ZYAN_ASSERT(instruction);
3982     ZYAN_ASSERT(index);
3983 
3984     /*if (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE)
3985     {
3986         instruction->raw.prefixes[context->prefixes.offset_asz_override].type =
3987             ZYDIS_PREFIX_TYPE_EFFECTIVE;
3988     }*/
3989     switch (instruction->machine_mode)
3990     {
3991     case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
3992     case ZYDIS_MACHINE_MODE_LEGACY_16:
3993     case ZYDIS_MACHINE_MODE_REAL_16:
3994         *index = (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 1 : 0;
3995         break;
3996     case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
3997     case ZYDIS_MACHINE_MODE_LEGACY_32:
3998         *index = (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 0 : 1;
3999         break;
4000     case ZYDIS_MACHINE_MODE_LONG_64:
4001         *index = (instruction->attributes & ZYDIS_ATTRIB_HAS_ADDRESSSIZE) ? 1 : 2;
4002         break;
4003     default:
4004         ZYAN_UNREACHABLE;
4005     }
4006 
4007     return ZYAN_STATUS_SUCCESS;
4008 }
4009 
4010 static ZyanStatus ZydisNodeHandlerVectorLength(const ZydisDecoderContext* context,
4011     const ZydisDecodedInstruction* instruction, ZyanU16* index)
4012 {
4013     ZYAN_ASSERT(context);
4014     ZYAN_ASSERT(instruction);
4015     ZYAN_ASSERT(index);
4016 
4017     switch (instruction->encoding)
4018     {
4019     case ZYDIS_INSTRUCTION_ENCODING_XOP:
4020         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_XOP);
4021         break;
4022     case ZYDIS_INSTRUCTION_ENCODING_VEX:
4023         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX);
4024         break;
4025     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4026         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX);
4027         break;
4028     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4029         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX);
4030         break;
4031     default:
4032         ZYAN_UNREACHABLE;
4033     }
4034 
4035     *index = context->vector_unified.LL;
4036     if (*index == 3)
4037     {
4038         return ZYDIS_STATUS_DECODING_ERROR;
4039     }
4040     return ZYAN_STATUS_SUCCESS;
4041 }
4042 
4043 static ZyanStatus ZydisNodeHandlerRexW(const ZydisDecoderContext* context,
4044     const ZydisDecodedInstruction* instruction, ZyanU16* index)
4045 {
4046     ZYAN_ASSERT(context);
4047     ZYAN_ASSERT(instruction);
4048     ZYAN_ASSERT(index);
4049 
4050     switch (instruction->encoding)
4051     {
4052     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
4053         // nothing to do here
4054         break;
4055     case ZYDIS_INSTRUCTION_ENCODING_XOP:
4056         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_XOP);
4057         break;
4058     case ZYDIS_INSTRUCTION_ENCODING_VEX:
4059         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX);
4060         break;
4061     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4062         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX);
4063         break;
4064     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4065         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX);
4066         break;
4067     default:
4068         ZYAN_UNREACHABLE;
4069     }
4070     *index = context->vector_unified.W;
4071     return ZYAN_STATUS_SUCCESS;
4072 }
4073 
4074 static ZyanStatus ZydisNodeHandlerRexB(const ZydisDecoderContext* context,
4075     const ZydisDecodedInstruction* instruction, ZyanU16* index)
4076 {
4077     ZYAN_ASSERT(context);
4078     ZYAN_ASSERT(instruction);
4079     ZYAN_ASSERT(index);
4080 
4081     switch (instruction->encoding)
4082     {
4083     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
4084         // nothing to do here
4085         break;
4086     case ZYDIS_INSTRUCTION_ENCODING_XOP:
4087         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_XOP);
4088         break;
4089     case ZYDIS_INSTRUCTION_ENCODING_VEX:
4090         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_VEX);
4091         break;
4092     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4093         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX);
4094         break;
4095     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4096         ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX);
4097         break;
4098     default:
4099         ZYAN_UNREACHABLE;
4100     }
4101     *index = context->vector_unified.B;
4102     return ZYAN_STATUS_SUCCESS;
4103 }
4104 
4105 #ifndef ZYDIS_DISABLE_AVX512
4106 static ZyanStatus ZydisNodeHandlerEvexB(const ZydisDecodedInstruction* instruction, ZyanU16* index)
4107 {
4108     ZYAN_ASSERT(instruction);
4109     ZYAN_ASSERT(index);
4110 
4111     ZYAN_ASSERT(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX);
4112     ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_EVEX);
4113     *index = instruction->raw.evex.b;
4114     return ZYAN_STATUS_SUCCESS;
4115 }
4116 #endif
4117 
4118 #ifndef ZYDIS_DISABLE_KNC
4119 static ZyanStatus ZydisNodeHandlerMvexE(const ZydisDecodedInstruction* instruction, ZyanU16* index)
4120 {
4121     ZYAN_ASSERT(instruction);
4122     ZYAN_ASSERT(index);
4123 
4124     ZYAN_ASSERT(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);
4125     ZYAN_ASSERT(instruction->attributes & ZYDIS_ATTRIB_HAS_MVEX);
4126     *index = instruction->raw.mvex.E;
4127     return ZYAN_STATUS_SUCCESS;
4128 }
4129 #endif
4130 
4131 /* ---------------------------------------------------------------------------------------------- */
4132 
4133 /**
4134  * Populates the internal register id fields for `REG`, `RM`, `NDSNDD`, `BASE` and `INDEX`/`VIDX`
4135  * encoded operands and performs sanity checks.
4136  *
4137  * @param   context     A pointer to the `ZydisDecoderContext` struct.
4138  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
4139  * @param   def_reg     The type definition for the `.reg` encoded operand.
4140  * @param   def_rm      The type definition for the `.rm` encoded operand.
4141  * @param   def_ndsndd  The type definition for the `.vvvv` encoded operand.
4142  *
4143  * @return  A zyan status code.
4144  *
4145  * This function sets all unused register ids to `-1`. This rule does currently not apply to
4146  * `base` and `index`.
4147  *
4148  * Definition encoding:
4149  * - `def_reg`    -> `ZydisRegisterKind`
4150  * - `def_ndsndd` -> `ZydisRegisterKind`
4151  * - `def_rm`     -> `ZydisRegisterKind` (`.mod == 3`) or ZydisMemoryOperandType (`.mod != 3`)
4152  */
4153 static ZyanStatus ZydisPopulateRegisterIds(ZydisDecoderContext* context,
4154     const ZydisDecodedInstruction* instruction, ZyanU8 def_reg, ZyanU8 def_rm, ZyanU8 def_ndsndd)
4155 {
4156     ZYAN_ASSERT(context);
4157     ZYAN_ASSERT(instruction);
4158 
4159     const ZyanBool is_64_bit = (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64);
4160     const ZyanBool is_reg    = context->reg_info.is_mod_reg;
4161     const ZyanBool has_sib   = !is_reg && (instruction->raw.modrm.rm == 4);
4162     const ZyanBool has_vsib  = has_sib && (def_rm == ZYDIS_MEMOP_TYPE_VSIB);
4163 
4164     ZyanU8 id_reg    = instruction->raw.modrm.reg;
4165     ZyanU8 id_rm     = instruction->raw.modrm.rm;
4166     ZyanU8 id_ndsndd = is_64_bit ? context->vector_unified.vvvv : context->vector_unified.vvvv & 0x07;
4167     ZyanU8 id_base   = has_sib ? instruction->raw.sib.base : instruction->raw.modrm.rm;
4168     ZyanU8 id_index  = instruction->raw.sib.index;
4169 
4170     if (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_64)
4171     {
4172         const ZyanBool is_emvex = (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
4173                                   (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX);
4174 
4175         // The `index` extension by `.v'` is only valid for VSIB operands
4176         const ZyanU8 vsib_v2 = has_vsib ? context->vector_unified.V2 : 0;
4177         // The `rm` extension by `.X` is only valid for EVEX/MVEX instructions
4178         const ZyanU8 evex_x  = is_emvex ? context->vector_unified.X  : 0;
4179 
4180         id_reg    |= (context->vector_unified.R2 << 4) | (context->vector_unified.R << 3);
4181         id_rm     |= (evex_x                     << 4) | (context->vector_unified.B << 3);
4182         id_ndsndd |= (context->vector_unified.V2 << 4)                                   ;
4183         id_base   |=                                     (context->vector_unified.B << 3);
4184         id_index  |= (vsib_v2                    << 4) | (context->vector_unified.X << 3);
4185 
4186         // The masking emulates the actual CPU behavior and does not verify if the resulting ids
4187         // are actually valid for the given register kind.
4188 
4189         static const ZyanU8 mask_reg[ZYDIS_REGKIND_MAX_VALUE + 1] =
4190         {
4191             /* INVALID */ 0,
4192             /* GPR     */ (1 << 5) - 1,
4193             /* X87     */ (1 << 3) - 1, // ignore `.R`, ignore `.R'`
4194             /* MMX     */ (1 << 3) - 1, // ignore `.R`, ignore `.R'`
4195             /* VR      */ (1 << 5) - 1,
4196             /* TMM     */ (1 << 5) - 1,
4197             /* SEGMENT */ (1 << 3) - 1, // ignore `.R`, ignore `.R'`
4198             /* TEST    */ (1 << 3) - 1, // ignore `.R`, ignore `.R'`
4199             /* CONTROL */ (1 << 4) - 1, //              ignore `.R'`
4200             /* DEBUG   */ (1 << 4) - 1, //              ignore `.R'`
4201             /* MASK    */ (1 << 5) - 1,
4202             /* BOUND   */ (1 << 4) - 1  //              ignore `.R'`
4203         };
4204         id_reg &= mask_reg[def_reg];
4205 
4206         static const ZyanU8 mask_rm[ZYDIS_REGKIND_MAX_VALUE + 1] =
4207         {
4208             /* INVALID */ 0,
4209             /* GPR     */ (1 << 4) - 1, //              ignore `.X`
4210             /* X87     */ (1 << 3) - 1, // ignore `.B`, ignore `.X`
4211             /* MMX     */ (1 << 3) - 1, // ignore `.B`, ignore `.X`
4212             /* VR      */ (1 << 5) - 1,
4213             /* TMM     */ (1 << 4) - 1, //              ignore `.X`
4214             /* SEGMENT */ (1 << 3) - 1, // ignore `.B`, ignore `.X`
4215             /* TEST    */ (1 << 3) - 1, // ignore `.B`, ignore `.X`
4216             /* CONTROL */ (1 << 4) - 1, //              ignore `.X`
4217             /* DEBUG   */ (1 << 4) - 1, //              ignore `.X`
4218             /* MASK    */ (1 << 3) - 1, // ignore `.B`, ignore `.X`
4219             /* BOUND   */ (1 << 4) - 1  //              ignore `.X`
4220         };
4221         id_rm &= (is_reg ? mask_rm[def_rm] : 0xFF);
4222 
4223         // Commented out for future reference. Not required at the moment as it's always either
4224         // a "take all" or "take nothing" situation.
4225 
4226         //static const ZyanU8 mask_ndsndd[ZYDIS_REGKIND_MAX_VALUE + 1] =
4227         //{
4228         //    /* INVALID */ 0,
4229         //    /* GPR     */ (1 << 5) - 1,
4230         //    /* X87     */ 0,            // never encoded in `.vvvv`
4231         //    /* MMX     */ 0,            // never encoded in `.vvvv`
4232         //    /* VR      */ (1 << 5) - 1,
4233         //    /* TMM     */ (1 << 5) - 1,
4234         //    /* SEGMENT */ 0,            // never encoded in `.vvvv`
4235         //    /* TEST    */ 0,            // never encoded in `.vvvv`
4236         //    /* CONTROL */ 0,            // never encoded in `.vvvv`
4237         //    /* DEBUG   */ 0,            // never encoded in `.vvvv`
4238         //    /* MASK    */ (1 << 5) - 1,
4239         //    /* BOUND   */ 0             // never encoded in `.vvvv`
4240         //};
4241     }
4242 
4243     // Validate
4244 
4245     // `.vvvv` is not allowed, if the instruction does not encode a NDS/NDD operand
4246     if (!def_ndsndd && context->vector_unified.vvvv)
4247     {
4248         return ZYDIS_STATUS_BAD_REGISTER;
4249     }
4250     // `.v'` is not allowed, if the instruction does not encode a NDS/NDD or VSIB operand
4251     if (!def_ndsndd && !has_vsib && context->vector_unified.V2)
4252     {
4253         return ZYDIS_STATUS_BAD_REGISTER;
4254     }
4255 
4256     static const ZyanU8 available_regs[2][ZYDIS_REGKIND_MAX_VALUE + 1] =
4257     {
4258         // 16/32 bit mode
4259         {
4260             /* INVALID */ 255,
4261             /* GPR     */   8,
4262             /* X87     */   8,
4263             /* MMX     */   8,
4264             /* VR      */   8,
4265             /* TMM     */   8,
4266             /* SEGMENT */   6,
4267             /* TEST    */   8,
4268             /* CONTROL */   8,
4269             /* DEBUG   */   8,
4270             /* MASK    */   8,
4271             /* BOUND   */   4
4272         },
4273         // 64 bit mode
4274         {
4275             /* INVALID */ 255,
4276             /* GPR     */  16,
4277             /* X87     */   8,
4278             /* MMX     */   8,
4279             /* VR      */  32,
4280             /* TMM     */   8,
4281             /* SEGMENT */   6,
4282             /* TEST    */   8,
4283             /* CONTROL */  16,
4284             // Attempts to reference DR8..DR15 result in undefined opcode (#UD) exceptions. DR4 and
4285             // DR5 are only valid, if the debug extension (DE) flag in CR4 is set. As we can't
4286             // check this at runtime we just allow them.
4287             /* DEBUG   */   8,
4288             /* MASK    */   8,
4289             /* BOUND   */   4
4290         }
4291     };
4292 
4293     if ((id_reg >= available_regs[is_64_bit][def_reg]) ||
4294         (id_ndsndd >= available_regs[is_64_bit][def_ndsndd]) ||
4295         (is_reg && (id_rm >= available_regs[is_64_bit][def_rm])))
4296     {
4297         return ZYDIS_STATUS_BAD_REGISTER;
4298     }
4299 
4300     ZyanI8 id_cr = -1;
4301     if (def_reg == ZYDIS_REGKIND_CONTROL)
4302     {
4303         id_cr = id_reg;
4304     }
4305     if (is_reg && (def_rm == ZYDIS_REGKIND_CONTROL))
4306     {
4307         id_cr = id_rm;
4308     }
4309     if (id_cr >= 0)
4310     {
4311         // Attempts to reference CR1, CR5, CR6, CR7, and CR9..CR15 result in undefined opcode (#UD)
4312         // exceptions
4313         static const ZyanU8 lookup[16] =
4314         {
4315             1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0
4316         };
4317         ZYAN_ASSERT((ZyanUSize)id_cr < ZYAN_ARRAY_LENGTH(lookup));
4318         if (!lookup[id_cr])
4319         {
4320             return ZYDIS_STATUS_BAD_REGISTER;
4321         }
4322     }
4323 
4324     // Assign to context
4325 
4326     context->reg_info.id_reg    = def_reg          ? id_reg    : -1;
4327     context->reg_info.id_rm     = def_rm && is_reg ? id_rm     : -1;
4328     context->reg_info.id_ndsndd = def_ndsndd       ? id_ndsndd : -1;
4329     context->reg_info.id_base   = id_base;  // TODO: Set unused register to -1 as well
4330     context->reg_info.id_index  = id_index; // TODO: Set unused register to -1 as well
4331 
4332     return ZYAN_STATUS_SUCCESS;
4333 }
4334 
4335 /**
4336  * Checks for certain post-decode error-conditions.
4337  *
4338  * @param   state       A pointer to the `ZydisDecoderState` struct.
4339  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
4340  * @param   definition  A pointer to the `ZydisInstructionDefinition` struct.
4341  *
4342  * @return  A zyan status code.
4343  *
4344  * This function is called immediately after a valid instruction-definition was found.
4345  */
4346 static ZyanStatus ZydisCheckErrorConditions(ZydisDecoderState* state,
4347     const ZydisDecodedInstruction* instruction, const ZydisInstructionDefinition* definition)
4348 {
4349     ZYAN_ASSERT(state);
4350     ZYAN_ASSERT(instruction);
4351     ZYAN_ASSERT(definition);
4352 
4353     ZyanU8 def_reg                  = definition->op_reg;
4354     ZyanU8 def_rm                   = definition->op_rm;
4355     ZyanU8 def_ndsndd               = ZYDIS_REGKIND_INVALID;
4356     ZyanBool is_gather              = ZYAN_FALSE;
4357     ZyanBool no_source_dest_match   = ZYAN_FALSE;
4358     ZyanBool no_source_source_match = ZYAN_FALSE;
4359 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
4360     ZydisMaskPolicy mask_policy     = ZYDIS_MASK_POLICY_INVALID;
4361 #endif
4362 
4363     switch (instruction->encoding)
4364     {
4365     case ZYDIS_INSTRUCTION_ENCODING_LEGACY:
4366     {
4367         const ZydisInstructionDefinitionLEGACY* def =
4368             (const ZydisInstructionDefinitionLEGACY*)definition;
4369 
4370         if (def->requires_protected_mode &&
4371             (instruction->machine_mode == ZYDIS_MACHINE_MODE_REAL_16))
4372         {
4373             return ZYDIS_STATUS_DECODING_ERROR;
4374         }
4375 
4376         if (def->no_compat_mode &&
4377             ((instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_16) ||
4378              (instruction->machine_mode == ZYDIS_MACHINE_MODE_LONG_COMPAT_32)))
4379         {
4380             return ZYDIS_STATUS_DECODING_ERROR;
4381         }
4382 
4383         if (state->prefixes.has_lock && !def->accepts_LOCK)
4384         {
4385             return ZYDIS_STATUS_ILLEGAL_LOCK;
4386         }
4387         break;
4388     }
4389     case ZYDIS_INSTRUCTION_ENCODING_3DNOW:
4390     {
4391         break;
4392     }
4393     case ZYDIS_INSTRUCTION_ENCODING_XOP:
4394     {
4395         const ZydisInstructionDefinitionXOP* def =
4396             (const ZydisInstructionDefinitionXOP*)definition;
4397         def_ndsndd = def->op_ndsndd;
4398         break;
4399     }
4400     case ZYDIS_INSTRUCTION_ENCODING_VEX:
4401     {
4402         const ZydisInstructionDefinitionVEX* def =
4403             (const ZydisInstructionDefinitionVEX*)definition;
4404         def_ndsndd             = def->op_ndsndd;
4405         is_gather              = def->is_gather;
4406         no_source_source_match = def->no_source_source_match;
4407         break;
4408     }
4409     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4410     {
4411 #ifndef ZYDIS_DISABLE_AVX512
4412         const ZydisInstructionDefinitionEVEX* def =
4413             (const ZydisInstructionDefinitionEVEX*)definition;
4414         def_ndsndd           = def->op_ndsndd;
4415         is_gather            = def->is_gather;
4416         no_source_dest_match = def->no_source_dest_match;
4417         mask_policy          = def->mask_policy;
4418 
4419         // Check for invalid zero-mask
4420         if ((instruction->raw.evex.z) && (!def->accepts_zero_mask))
4421         {
4422             return ZYDIS_STATUS_INVALID_MASK; // TODO: Dedicated status code
4423         }
4424 #else
4425         ZYAN_UNREACHABLE;
4426 #endif
4427         break;
4428     }
4429     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4430     {
4431 #ifndef ZYDIS_DISABLE_KNC
4432         const ZydisInstructionDefinitionMVEX* def =
4433             (const ZydisInstructionDefinitionMVEX*)definition;
4434         def_ndsndd  = def->op_ndsndd;
4435         is_gather   = def->is_gather;
4436         mask_policy = def->mask_policy;
4437 
4438         // Check for invalid MVEX.SSS values
4439         static const ZyanU8 lookup[26][8] =
4440         {
4441             // ZYDIS_MVEX_FUNC_IGNORED
4442             { 1, 1, 1, 1, 1, 1, 1, 1 },
4443             // ZYDIS_MVEX_FUNC_INVALID
4444             { 1, 0, 0, 0, 0, 0, 0, 0 },
4445             // ZYDIS_MVEX_FUNC_RC
4446             { 1, 1, 1, 1, 1, 1, 1, 1 },
4447             // ZYDIS_MVEX_FUNC_SAE
4448             { 1, 1, 1, 1, 1, 1, 1, 1 },
4449             // ZYDIS_MVEX_FUNC_F_32
4450             { 1, 0, 0, 0, 0, 0, 0, 0 },
4451             // ZYDIS_MVEX_FUNC_I_32
4452             { 1, 0, 0, 0, 0, 0, 0, 0 },
4453             // ZYDIS_MVEX_FUNC_F_64
4454             { 1, 0, 0, 0, 0, 0, 0, 0 },
4455             // ZYDIS_MVEX_FUNC_I_64
4456             { 1, 0, 0, 0, 0, 0, 0, 0 },
4457             // ZYDIS_MVEX_FUNC_SWIZZLE_32
4458             { 1, 1, 1, 1, 1, 1, 1, 1 },
4459             // ZYDIS_MVEX_FUNC_SWIZZLE_64
4460             { 1, 1, 1, 1, 1, 1, 1, 1 },
4461             // ZYDIS_MVEX_FUNC_SF_32
4462             { 1, 1, 1, 1, 1, 0, 1, 1 },
4463             // ZYDIS_MVEX_FUNC_SF_32_BCST
4464             { 1, 1, 1, 0, 0, 0, 0, 0 },
4465             // ZYDIS_MVEX_FUNC_SF_32_BCST_4TO16
4466             { 1, 0, 1, 0, 0, 0, 0, 0 },
4467             // ZYDIS_MVEX_FUNC_SF_64
4468             { 1, 1, 1, 0, 0, 0, 0, 0 },
4469             // ZYDIS_MVEX_FUNC_SI_32
4470             { 1, 1, 1, 0, 1, 1, 1, 1 },
4471             // ZYDIS_MVEX_FUNC_SI_32_BCST
4472             { 1, 1, 1, 0, 0, 0, 0, 0 },
4473             // ZYDIS_MVEX_FUNC_SI_32_BCST_4TO16
4474             { 1, 0, 1, 0, 0, 0, 0, 0 },
4475             // ZYDIS_MVEX_FUNC_SI_64
4476             { 1, 1, 1, 0, 0, 0, 0, 0 },
4477             // ZYDIS_MVEX_FUNC_UF_32
4478             { 1, 0, 0, 1, 1, 1, 1, 1 },
4479             // ZYDIS_MVEX_FUNC_UF_64
4480             { 1, 0, 0, 0, 0, 0, 0, 0 },
4481             // ZYDIS_MVEX_FUNC_UI_32
4482             { 1, 0, 0, 0, 1, 1, 1, 1 },
4483             // ZYDIS_MVEX_FUNC_UI_64
4484             { 1, 0, 0, 0, 0, 0, 0, 0 },
4485             // ZYDIS_MVEX_FUNC_DF_32
4486             { 1, 0, 0, 1, 1, 1, 1, 1 },
4487             // ZYDIS_MVEX_FUNC_DF_64
4488             { 1, 0, 0, 0, 0, 0, 0, 0 },
4489             // ZYDIS_MVEX_FUNC_DI_32
4490             { 1, 0, 0, 0, 1, 1, 1, 1 },
4491             // ZYDIS_MVEX_FUNC_DI_64
4492             { 1, 0, 0, 0, 0, 0, 0, 0 }
4493         };
4494         ZYAN_ASSERT(def->functionality < ZYAN_ARRAY_LENGTH(lookup));
4495         ZYAN_ASSERT(instruction->raw.mvex.SSS < 8);
4496         if (!lookup[def->functionality][instruction->raw.mvex.SSS])
4497         {
4498             return ZYDIS_STATUS_DECODING_ERROR;
4499         }
4500 #else
4501         ZYAN_UNREACHABLE;
4502 #endif
4503         break;
4504     }
4505     default:
4506         ZYAN_UNREACHABLE;
4507     }
4508 
4509     ZydisDecoderContext* context = state->context;
4510     const ZyanBool is_reg = context->reg_info.is_mod_reg;
4511 
4512     ZyanU8 no_rip_rel     = ZYAN_FALSE;
4513     ZyanU8 is_sr_dest_reg = ZYAN_FALSE;
4514     ZyanU8 is_sr_dest_rm  = ZYAN_FALSE;
4515     if (def_reg)
4516     {
4517         is_sr_dest_reg = ZYDIS_OPDEF_GET_REG_HIGH_BIT(def_reg);
4518         def_reg = ZYDIS_OPDEF_GET_REG(def_reg);
4519     }
4520     if (def_rm)
4521     {
4522         if (is_reg)
4523         {
4524             is_sr_dest_rm = ZYDIS_OPDEF_GET_REG_HIGH_BIT(def_rm);
4525             def_rm = ZYDIS_OPDEF_GET_REG(def_rm);
4526         }
4527         else
4528         {
4529             no_rip_rel = ZYDIS_OPDEF_GET_MEM_HIGH_BIT(def_rm);
4530             def_rm = ZYDIS_OPDEF_GET_MEM(def_rm);
4531         }
4532     }
4533 
4534     // Check RIP-relative memory addressing
4535     if (no_rip_rel)
4536     {
4537         const ZyanBool is_rip_rel =
4538             (state->decoder->machine_mode == ZYDIS_MACHINE_MODE_LONG_64) &&
4539             (instruction->raw.modrm.mod == 0) && (instruction->raw.modrm.rm == 5);
4540         if (is_rip_rel)
4541         {
4542             return ZYDIS_STATUS_BAD_REGISTER;
4543         }
4544     }
4545 
4546     // Populate- and validate register constraints
4547     ZYAN_CHECK(ZydisPopulateRegisterIds(context, instruction, def_reg, def_rm, def_ndsndd));
4548 
4549     // `ZYDIS_REGISTER_CS` is not allowed as `MOV` target
4550     if (is_sr_dest_reg && (context->reg_info.id_reg == 1))
4551     {
4552         return ZYDIS_STATUS_BAD_REGISTER;
4553     }
4554     if (is_sr_dest_rm && (context->reg_info.id_rm == 1))
4555     {
4556         return ZYDIS_STATUS_BAD_REGISTER;
4557     }
4558 
4559     // Check gather registers
4560     if (is_gather)
4561     {
4562         // ZYAN_ASSERT(has_VSIB);
4563         ZYAN_ASSERT(instruction->raw.modrm.mod != 3);
4564         ZYAN_ASSERT(instruction->raw.modrm.rm  == 4);
4565 
4566         const ZyanU8 index = context->reg_info.id_index;
4567         ZyanU8 dest        = context->reg_info.id_reg;
4568         ZyanU8 mask        = 0xF0;
4569 
4570         if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX)
4571         {
4572             ZYAN_ASSERT((def_reg    == ZYDIS_REGKIND_VR) &&
4573                         (def_rm     == ZYDIS_MEMOP_TYPE_VSIB) &&
4574                         (def_ndsndd == ZYDIS_REGKIND_VR));
4575             mask = context->reg_info.id_ndsndd;
4576         }
4577 
4578         if ((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
4579             (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_MVEX))
4580         {
4581             ZYAN_ASSERT(((def_reg    == ZYDIS_REGKIND_INVALID) ||
4582                          (def_reg    == ZYDIS_REGKIND_VR)) &&
4583                          (def_rm     == ZYDIS_MEMOP_TYPE_VSIB) &&
4584                          (def_ndsndd == ZYDIS_REGKIND_INVALID));
4585 
4586             // Some gather instructions (like `VGATHERPF0{D|Q}{PS|PD}`) do not have a destination
4587             // operand
4588             if (!def_reg)
4589             {
4590                 dest = 0xF1;
4591             }
4592         }
4593 
4594         // If any pair of the index, mask, or destination registers are the same, the instruction
4595         // results a UD fault
4596         if ((dest == index) || (dest == mask) || (index == mask))
4597         {
4598             return ZYDIS_STATUS_BAD_REGISTER;
4599         }
4600     }
4601 
4602     // Check if any source register matches the destination register
4603     if (no_source_dest_match)
4604     {
4605         ZYAN_ASSERT((instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_EVEX) ||
4606                     (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX));
4607 
4608         const ZyanU8 dest    = context->reg_info.id_reg;
4609         const ZyanU8 source1 = context->reg_info.id_ndsndd;
4610         const ZyanU8 source2 = context->reg_info.id_rm;
4611 
4612         if ((dest == source1) || (is_reg && (dest == source2)))
4613         {
4614             return ZYDIS_STATUS_BAD_REGISTER;
4615         }
4616     }
4617 
4618     // If any pair of the source or destination registers are the same, the instruction results a
4619     // UD fault
4620     if (no_source_source_match) // TODO: Find better name
4621     {
4622         ZYAN_ASSERT(instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_VEX);
4623         ZYAN_ASSERT(is_reg);
4624 
4625         const ZyanU8 dest    = context->reg_info.id_reg;
4626         const ZyanU8 source1 = context->reg_info.id_ndsndd;
4627         const ZyanU8 source2 = context->reg_info.id_rm;
4628 
4629         if ((dest == source1) || (dest == source2) || (source1 == source2))
4630         {
4631             return ZYDIS_STATUS_BAD_REGISTER;
4632         }
4633     }
4634 
4635 #if !defined(ZYDIS_DISABLE_AVX512) || !defined(ZYDIS_DISABLE_KNC)
4636     // Check for invalid MASK registers
4637     switch (mask_policy)
4638     {
4639     case ZYDIS_MASK_POLICY_INVALID:
4640     case ZYDIS_MASK_POLICY_ALLOWED:
4641         // Nothing to do here
4642         break;
4643     case ZYDIS_MASK_POLICY_REQUIRED:
4644         if (!context->vector_unified.mask)
4645         {
4646             return ZYDIS_STATUS_INVALID_MASK;
4647         }
4648         break;
4649     case ZYDIS_MASK_POLICY_FORBIDDEN:
4650         if (context->vector_unified.mask)
4651         {
4652             return ZYDIS_STATUS_INVALID_MASK;
4653         }
4654         break;
4655     default:
4656         ZYAN_UNREACHABLE;
4657     }
4658 #endif
4659 
4660     return ZYAN_STATUS_SUCCESS;
4661 }
4662 
4663 /* ---------------------------------------------------------------------------------------------- */
4664 
4665 /**
4666  * Uses the decoder-tree to decode the current instruction.
4667  *
4668  * @param   state       A pointer to the `ZydisDecoderState` struct.
4669  * @param   instruction A pointer to the `ZydisDecodedInstruction` struct.
4670  *
4671  * @return  A zyan status code.
4672  */
4673 static ZyanStatus ZydisDecodeInstruction(ZydisDecoderState* state,
4674     ZydisDecodedInstruction* instruction)
4675 {
4676     ZYAN_ASSERT(state);
4677     ZYAN_ASSERT(instruction);
4678 
4679     // Iterate through the decoder tree
4680     const ZydisDecoderTreeNode* node = ZydisDecoderTreeGetRootNode();
4681     const ZydisDecoderTreeNode* temp = ZYAN_NULL;
4682     ZydisDecoderTreeNodeType node_type;
4683     do
4684     {
4685         node_type = node->type;
4686         ZyanU16 index = 0;
4687         ZyanStatus status = 0;
4688         switch (node_type)
4689         {
4690         case ZYDIS_NODETYPE_INVALID:
4691             if (temp)
4692             {
4693                 node = temp;
4694                 temp = ZYAN_NULL;
4695                 node_type = ZYDIS_NODETYPE_FILTER_MANDATORY_PREFIX;
4696                 if (state->prefixes.mandatory_candidate != 0x00)
4697                 {
4698                     instruction->raw.prefixes[state->prefixes.offset_mandatory].type =
4699                         ZYDIS_PREFIX_TYPE_IGNORED;
4700                 }
4701                 if (state->prefixes.mandatory_candidate == 0x66)
4702                 {
4703                     if (state->prefixes.offset_osz_override ==
4704                         state->prefixes.offset_mandatory)
4705                     {
4706                         instruction->raw.prefixes[state->prefixes.offset_mandatory].type =
4707                             ZYDIS_PREFIX_TYPE_EFFECTIVE;
4708                     }
4709                     instruction->attributes |= ZYDIS_ATTRIB_HAS_OPERANDSIZE;
4710                 }
4711                 continue;
4712             }
4713             return ZYDIS_STATUS_DECODING_ERROR;
4714         case ZYDIS_NODETYPE_FILTER_XOP:
4715             status = ZydisNodeHandlerXOP(instruction, &index);
4716             break;
4717         case ZYDIS_NODETYPE_FILTER_VEX:
4718             status = ZydisNodeHandlerVEX(instruction, &index);
4719             break;
4720         case ZYDIS_NODETYPE_FILTER_EMVEX:
4721             status = ZydisNodeHandlerEMVEX(instruction, &index);
4722             break;
4723         case ZYDIS_NODETYPE_FILTER_OPCODE:
4724             status = ZydisNodeHandlerOpcode(state, instruction, &index);
4725             break;
4726         case ZYDIS_NODETYPE_FILTER_MODE:
4727             status = ZydisNodeHandlerMode(instruction, &index);
4728             break;
4729         case ZYDIS_NODETYPE_FILTER_MODE_COMPACT:
4730             status = ZydisNodeHandlerModeCompact(instruction, &index);
4731             break;
4732         case ZYDIS_NODETYPE_FILTER_MODRM_MOD:
4733             status = ZydisNodeHandlerModrmMod(state, instruction, &index);
4734             break;
4735         case ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT:
4736             status = ZydisNodeHandlerModrmModCompact(state, instruction, &index);
4737             break;
4738         case ZYDIS_NODETYPE_FILTER_MODRM_REG:
4739             status = ZydisNodeHandlerModrmReg(state, instruction, &index);
4740             break;
4741         case ZYDIS_NODETYPE_FILTER_MODRM_RM:
4742             status = ZydisNodeHandlerModrmRm(state, instruction, &index);
4743             break;
4744         case ZYDIS_NODETYPE_FILTER_PREFIX_GROUP1:
4745             index = state->prefixes.group1 ? 1 : 0;
4746             break;
4747         case ZYDIS_NODETYPE_FILTER_MANDATORY_PREFIX:
4748             status = ZydisNodeHandlerMandatoryPrefix(state, instruction, &index);
4749             temp = ZydisDecoderTreeGetChildNode(node, 0);
4750             // TODO: Return to this point, if index == 0 contains a value and the previous path
4751             // TODO: was not successful
4752             // TODO: Restore consumed prefix
4753             break;
4754         case ZYDIS_NODETYPE_FILTER_OPERAND_SIZE:
4755             status = ZydisNodeHandlerOperandSize(state, instruction, &index);
4756             break;
4757         case ZYDIS_NODETYPE_FILTER_ADDRESS_SIZE:
4758             status = ZydisNodeHandlerAddressSize(instruction, &index);
4759             break;
4760         case ZYDIS_NODETYPE_FILTER_VECTOR_LENGTH:
4761             status = ZydisNodeHandlerVectorLength(state->context, instruction, &index);
4762             break;
4763         case ZYDIS_NODETYPE_FILTER_REX_W:
4764             status = ZydisNodeHandlerRexW(state->context, instruction, &index);
4765             break;
4766         case ZYDIS_NODETYPE_FILTER_REX_B:
4767             status = ZydisNodeHandlerRexB(state->context, instruction, &index);
4768             break;
4769 #ifndef ZYDIS_DISABLE_AVX512
4770         case ZYDIS_NODETYPE_FILTER_EVEX_B:
4771             status = ZydisNodeHandlerEvexB(instruction, &index);
4772             break;
4773 #endif
4774 #ifndef ZYDIS_DISABLE_KNC
4775         case ZYDIS_NODETYPE_FILTER_MVEX_E:
4776             status = ZydisNodeHandlerMvexE(instruction, &index);
4777             break;
4778 #endif
4779         case ZYDIS_NODETYPE_FILTER_MODE_AMD:
4780             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_AMD_BRANCHES));
4781             break;
4782         case ZYDIS_NODETYPE_FILTER_MODE_KNC:
4783             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_KNC));
4784             break;
4785         case ZYDIS_NODETYPE_FILTER_MODE_MPX:
4786             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_MPX));
4787             break;
4788         case ZYDIS_NODETYPE_FILTER_MODE_CET:
4789             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_CET));
4790             break;
4791         case ZYDIS_NODETYPE_FILTER_MODE_LZCNT:
4792             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_LZCNT));
4793             break;
4794         case ZYDIS_NODETYPE_FILTER_MODE_TZCNT:
4795             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_TZCNT));
4796             break;
4797         case ZYDIS_NODETYPE_FILTER_MODE_WBNOINVD:
4798             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_WBNOINVD));
4799             break;
4800         case ZYDIS_NODETYPE_FILTER_MODE_CLDEMOTE:
4801             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_CLDEMOTE));
4802             break;
4803         case ZYDIS_NODETYPE_FILTER_MODE_IPREFETCH:
4804             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_IPREFETCH));
4805             break;
4806         case ZYDIS_NODETYPE_FILTER_MODE_UD0_COMPAT:
4807             index = !!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_UD0_COMPAT));
4808             break;
4809         default:
4810             if (node_type & ZYDIS_NODETYPE_DEFINITION_MASK)
4811             {
4812                 const ZydisInstructionDefinition* definition;
4813                 ZydisGetInstructionDefinition(instruction->encoding, node->value, &definition);
4814                 ZydisSetEffectiveOperandWidth(state->context, instruction, definition);
4815                 ZydisSetEffectiveAddressWidth(state->context, instruction, definition);
4816 
4817                 const ZydisInstructionEncodingInfo* info;
4818                 ZydisGetInstructionEncodingInfo(node, &info);
4819                 ZYAN_CHECK(ZydisDecodeOptionalInstructionParts(state, instruction, info));
4820                 ZYAN_CHECK(ZydisCheckErrorConditions(state, instruction, definition));
4821 
4822                 if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
4823                 {
4824                     // Get actual 3DNOW opcode and definition
4825                     ZYAN_CHECK(ZydisInputNext(state, instruction, &instruction->opcode));
4826                     node = ZydisDecoderTreeGetRootNode();
4827                     node = ZydisDecoderTreeGetChildNode(node, 0x0F);
4828                     node = ZydisDecoderTreeGetChildNode(node, 0x0F);
4829                     node = ZydisDecoderTreeGetChildNode(node, instruction->opcode);
4830                     if (node->type == ZYDIS_NODETYPE_INVALID)
4831                     {
4832                         return ZYDIS_STATUS_DECODING_ERROR;
4833                     }
4834                     ZYAN_ASSERT(node->type == ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT);
4835                     node = ZydisDecoderTreeGetChildNode(
4836                         node, (instruction->raw.modrm.mod == 0x3) ? 0 : 1);
4837                     ZYAN_ASSERT(node->type & ZYDIS_NODETYPE_DEFINITION_MASK);
4838                     ZydisGetInstructionDefinition(instruction->encoding, node->value, &definition);
4839                 }
4840 
4841                 instruction->mnemonic = definition->mnemonic;
4842 
4843 #ifndef ZYDIS_MINIMAL_MODE
4844 
4845                 instruction->operand_count = definition->operand_count;
4846                 instruction->operand_count_visible = definition->operand_count_visible;
4847                 state->context->definition = definition;
4848 
4849                 instruction->meta.category = definition->category;
4850                 instruction->meta.isa_set = definition->isa_set;
4851                 instruction->meta.isa_ext = definition->isa_ext;
4852                 instruction->meta.branch_type = definition->branch_type;
4853                 ZYAN_ASSERT((instruction->meta.branch_type == ZYDIS_BRANCH_TYPE_NONE) ||
4854                         ((instruction->meta.category == ZYDIS_CATEGORY_CALL) ||
4855                          (instruction->meta.category == ZYDIS_CATEGORY_COND_BR) ||
4856                          (instruction->meta.category == ZYDIS_CATEGORY_UNCOND_BR) ||
4857                          (instruction->meta.category == ZYDIS_CATEGORY_RET)));
4858                 instruction->meta.exception_class = definition->exception_class;
4859 
4860                 if (!(state->decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_MINIMAL)))
4861                 {
4862                     ZydisSetAttributes(state, instruction, definition);
4863                     switch (instruction->encoding)
4864                     {
4865                     case ZYDIS_INSTRUCTION_ENCODING_XOP:
4866                     case ZYDIS_INSTRUCTION_ENCODING_VEX:
4867                     case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4868                     case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4869                         ZydisSetAVXInformation(state->context, instruction, definition);
4870                         break;
4871                     default:
4872                         break;
4873                     }
4874 
4875                     const ZydisDefinitionAccessedFlags* flags;
4876                     if (ZydisGetAccessedFlags(definition, &flags))
4877                     {
4878                         instruction->attributes |= ZYDIS_ATTRIB_CPUFLAG_ACCESS;
4879                     }
4880                     instruction->cpu_flags = &flags->cpu_flags;
4881                     instruction->fpu_flags = &flags->fpu_flags;
4882                 }
4883 
4884 #endif
4885 
4886                 return ZYAN_STATUS_SUCCESS;
4887             }
4888             ZYAN_UNREACHABLE;
4889         }
4890         ZYAN_CHECK(status);
4891         node = ZydisDecoderTreeGetChildNode(node, index);
4892     } while ((node_type != ZYDIS_NODETYPE_INVALID) && !(node_type & ZYDIS_NODETYPE_DEFINITION_MASK));
4893     return ZYAN_STATUS_SUCCESS;
4894 }
4895 
4896 /* ---------------------------------------------------------------------------------------------- */
4897 
4898 /* ============================================================================================== */
4899 /* Exported functions                                                                             */
4900 /* ============================================================================================== */
4901 
4902 ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode,
4903     ZydisStackWidth stack_width)
4904 {
4905     ZYAN_STATIC_ASSERT(ZYDIS_DECODER_MODE_MAX_VALUE <= 32);
4906 
4907     static const ZyanU32 decoder_modes =
4908 #ifdef ZYDIS_MINIMAL_MODE
4909         (1 << ZYDIS_DECODER_MODE_MINIMAL) |
4910 #endif
4911         (1 << ZYDIS_DECODER_MODE_MPX) |
4912         (1 << ZYDIS_DECODER_MODE_CET) |
4913         (1 << ZYDIS_DECODER_MODE_LZCNT) |
4914         (1 << ZYDIS_DECODER_MODE_TZCNT) |
4915         (1 << ZYDIS_DECODER_MODE_CLDEMOTE) |
4916         (1 << ZYDIS_DECODER_MODE_IPREFETCH);
4917 
4918     if (!decoder)
4919     {
4920         return ZYAN_STATUS_INVALID_ARGUMENT;
4921     }
4922     switch (machine_mode)
4923     {
4924     case ZYDIS_MACHINE_MODE_LONG_64:
4925         if (stack_width != ZYDIS_STACK_WIDTH_64)
4926         {
4927             return ZYAN_STATUS_INVALID_ARGUMENT;
4928         }
4929         break;
4930     case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
4931     case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
4932     case ZYDIS_MACHINE_MODE_LEGACY_32:
4933     case ZYDIS_MACHINE_MODE_LEGACY_16:
4934     case ZYDIS_MACHINE_MODE_REAL_16:
4935         if ((stack_width != ZYDIS_STACK_WIDTH_16) && (stack_width != ZYDIS_STACK_WIDTH_32))
4936         {
4937             return ZYAN_STATUS_INVALID_ARGUMENT;
4938         }
4939         break;
4940     default:
4941         return ZYAN_STATUS_INVALID_ARGUMENT;
4942     }
4943 
4944     decoder->machine_mode = machine_mode;
4945     decoder->stack_width = stack_width;
4946     decoder->decoder_mode = decoder_modes;
4947 
4948     return ZYAN_STATUS_SUCCESS;
4949 }
4950 
4951 ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode, ZyanBool enabled)
4952 {
4953     if (!decoder || ((ZyanUSize)mode > ZYDIS_DECODER_MODE_MAX_VALUE))
4954     {
4955         return ZYAN_STATUS_INVALID_ARGUMENT;
4956     }
4957 
4958 #ifdef ZYDIS_MINIMAL_MODE
4959     if ((mode == ZYDIS_DECODER_MODE_MINIMAL) && !enabled)
4960     {
4961         return ZYAN_STATUS_INVALID_OPERATION;
4962     }
4963 #endif
4964 
4965     if (enabled)
4966     {
4967         decoder->decoder_mode |= (1 << mode);
4968     }
4969     else
4970     {
4971         decoder->decoder_mode &= ~(1 << mode);
4972     }
4973 
4974     return ZYAN_STATUS_SUCCESS;
4975 }
4976 
4977 ZyanStatus ZydisDecoderDecodeFull(const ZydisDecoder* decoder,
4978     const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction,
4979     ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT])
4980 {
4981     if (!decoder || !instruction || !buffer || !operands)
4982     {
4983         return ZYAN_STATUS_INVALID_ARGUMENT;
4984     }
4985     if (!length)
4986     {
4987         return ZYDIS_STATUS_NO_MORE_DATA;
4988     }
4989     if (decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_MINIMAL))
4990     {
4991         return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
4992     }
4993 
4994     ZydisDecoderContext context;
4995     ZYAN_CHECK(ZydisDecoderDecodeInstruction(decoder, &context, buffer, length, instruction));
4996     ZYAN_CHECK(ZydisDecoderDecodeOperands(decoder, &context, instruction, operands,
4997         instruction->operand_count));
4998     ZYAN_MEMSET(&operands[instruction->operand_count], 0,
4999         (ZYDIS_MAX_OPERAND_COUNT - instruction->operand_count) * sizeof(operands[0]));
5000 
5001     return ZYAN_STATUS_SUCCESS;
5002 }
5003 
5004 ZyanStatus ZydisDecoderDecodeInstruction(const ZydisDecoder* decoder, ZydisDecoderContext* context,
5005     const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction)
5006 {
5007     if (!decoder || !instruction || !buffer)
5008     {
5009         return ZYAN_STATUS_INVALID_ARGUMENT;
5010     }
5011 
5012     if (!length)
5013     {
5014         return ZYDIS_STATUS_NO_MORE_DATA;
5015     }
5016 
5017     ZydisDecoderState state;
5018     ZYAN_MEMSET(&state, 0, sizeof(state));
5019     state.decoder = decoder;
5020     state.buffer = (const ZyanU8*)buffer;
5021     state.buffer_len = length;
5022     state.prefixes.offset_notrack = -1;
5023 
5024     ZydisDecoderContext default_context;
5025     if (!context)
5026     {
5027         // Use a fallback context if no custom one has been provided
5028         context = &default_context;
5029     }
5030     ZYAN_MEMSET(context, 0, sizeof(*context));
5031     state.context = context;
5032 
5033     ZYAN_MEMSET(instruction, 0, sizeof(*instruction));
5034     instruction->machine_mode = decoder->machine_mode;
5035     instruction->stack_width = 16 << decoder->stack_width;
5036 
5037     ZYAN_CHECK(ZydisCollectOptionalPrefixes(&state, instruction));
5038     ZYAN_CHECK(ZydisDecodeInstruction(&state, instruction));
5039 
5040     instruction->raw.encoding2 = instruction->encoding;
5041 
5042     return ZYAN_STATUS_SUCCESS;
5043 }
5044 
5045 ZyanStatus ZydisDecoderDecodeOperands(const ZydisDecoder* decoder,
5046     const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
5047     ZydisDecodedOperand* operands, ZyanU8 operand_count)
5048 {
5049 #ifdef ZYDIS_MINIMAL_MODE
5050 
5051     ZYAN_UNUSED(decoder);
5052     ZYAN_UNUSED(context);
5053     ZYAN_UNUSED(instruction);
5054     ZYAN_UNUSED(operands);
5055     ZYAN_UNUSED(operand_count);
5056 
5057     return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
5058 
5059 #else
5060 
5061     if (!decoder || !context || !context->definition || !instruction ||
5062         (operand_count && !operands) || (operand_count > ZYDIS_MAX_OPERAND_COUNT))
5063     {
5064         return ZYAN_STATUS_INVALID_ARGUMENT;
5065     }
5066 
5067     if (decoder->decoder_mode & (1 << ZYDIS_DECODER_MODE_MINIMAL))
5068     {
5069         return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
5070     }
5071 
5072     operand_count = ZYAN_MIN(operand_count, instruction->operand_count);
5073     if (!operand_count)
5074     {
5075         return ZYAN_STATUS_SUCCESS;
5076     }
5077 
5078     return ZydisDecodeOperands(decoder, context, instruction, operands, operand_count);
5079 
5080 #endif
5081 }
5082 
5083 /* ============================================================================================== */
5084