/ externals / zydis / src / Decoder.c
Decoder.c
   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  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[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[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[ZYDIS_DECODER_MODE_AMD_BRANCHES] ? 1 : 0;
4781              break;
4782          case ZYDIS_NODETYPE_FILTER_MODE_KNC:
4783              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_KNC] ? 1 : 0;
4784              break;
4785          case ZYDIS_NODETYPE_FILTER_MODE_MPX:
4786              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_MPX] ? 1 : 0;
4787              break;
4788          case ZYDIS_NODETYPE_FILTER_MODE_CET:
4789              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_CET] ? 1 : 0;
4790              break;
4791          case ZYDIS_NODETYPE_FILTER_MODE_LZCNT:
4792              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_LZCNT] ? 1 : 0;
4793              break;
4794          case ZYDIS_NODETYPE_FILTER_MODE_TZCNT:
4795              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_TZCNT] ? 1 : 0;
4796              break;
4797          case ZYDIS_NODETYPE_FILTER_MODE_WBNOINVD:
4798              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_WBNOINVD] ? 1 : 0;
4799              break;
4800          case ZYDIS_NODETYPE_FILTER_MODE_CLDEMOTE:
4801              index = state->decoder->decoder_mode[ZYDIS_DECODER_MODE_CLDEMOTE] ? 1 : 0;
4802              break;
4803          default:
4804              if (node_type & ZYDIS_NODETYPE_DEFINITION_MASK)
4805              {
4806                  const ZydisInstructionDefinition* definition;
4807                  ZydisGetInstructionDefinition(instruction->encoding, node->value, &definition);
4808                  ZydisSetEffectiveOperandWidth(state->context, instruction, definition);
4809                  ZydisSetEffectiveAddressWidth(state->context, instruction, definition);
4810  
4811                  const ZydisInstructionEncodingInfo* info;
4812                  ZydisGetInstructionEncodingInfo(node, &info);
4813                  ZYAN_CHECK(ZydisDecodeOptionalInstructionParts(state, instruction, info));
4814                  ZYAN_CHECK(ZydisCheckErrorConditions(state, instruction, definition));
4815  
4816                  if (instruction->encoding == ZYDIS_INSTRUCTION_ENCODING_3DNOW)
4817                  {
4818                      // Get actual 3DNOW opcode and definition
4819                      ZYAN_CHECK(ZydisInputNext(state, instruction, &instruction->opcode));
4820                      node = ZydisDecoderTreeGetRootNode();
4821                      node = ZydisDecoderTreeGetChildNode(node, 0x0F);
4822                      node = ZydisDecoderTreeGetChildNode(node, 0x0F);
4823                      node = ZydisDecoderTreeGetChildNode(node, instruction->opcode);
4824                      if (node->type == ZYDIS_NODETYPE_INVALID)
4825                      {
4826                          return ZYDIS_STATUS_DECODING_ERROR;
4827                      }
4828                      ZYAN_ASSERT(node->type == ZYDIS_NODETYPE_FILTER_MODRM_MOD_COMPACT);
4829                      node = ZydisDecoderTreeGetChildNode(
4830                          node, (instruction->raw.modrm.mod == 0x3) ? 0 : 1);
4831                      ZYAN_ASSERT(node->type & ZYDIS_NODETYPE_DEFINITION_MASK);
4832                      ZydisGetInstructionDefinition(instruction->encoding, node->value, &definition);
4833                  }
4834  
4835                  instruction->mnemonic = definition->mnemonic;
4836  
4837  #ifndef ZYDIS_MINIMAL_MODE
4838  
4839                  instruction->operand_count = definition->operand_count;
4840                  instruction->operand_count_visible = definition->operand_count_visible;
4841                  state->context->definition = definition;
4842  
4843                  instruction->meta.category = definition->category;
4844                  instruction->meta.isa_set = definition->isa_set;
4845                  instruction->meta.isa_ext = definition->isa_ext;
4846                  instruction->meta.branch_type = definition->branch_type;
4847                  ZYAN_ASSERT((instruction->meta.branch_type == ZYDIS_BRANCH_TYPE_NONE) ||
4848                          ((instruction->meta.category == ZYDIS_CATEGORY_CALL) ||
4849                           (instruction->meta.category == ZYDIS_CATEGORY_COND_BR) ||
4850                           (instruction->meta.category == ZYDIS_CATEGORY_UNCOND_BR) ||
4851                           (instruction->meta.category == ZYDIS_CATEGORY_RET)));
4852                  instruction->meta.exception_class = definition->exception_class;
4853  
4854                  if (!state->decoder->decoder_mode[ZYDIS_DECODER_MODE_MINIMAL])
4855                  {
4856                      ZydisSetAttributes(state, instruction, definition);
4857                      switch (instruction->encoding)
4858                      {
4859                      case ZYDIS_INSTRUCTION_ENCODING_XOP:
4860                      case ZYDIS_INSTRUCTION_ENCODING_VEX:
4861                      case ZYDIS_INSTRUCTION_ENCODING_EVEX:
4862                      case ZYDIS_INSTRUCTION_ENCODING_MVEX:
4863                          ZydisSetAVXInformation(state->context, instruction, definition);
4864                          break;
4865                      default:
4866                          break;
4867                      }
4868  
4869                      const ZydisDefinitionAccessedFlags* flags;
4870                      if (ZydisGetAccessedFlags(definition, &flags))
4871                      {
4872                          instruction->attributes |= ZYDIS_ATTRIB_CPUFLAG_ACCESS;
4873                      }
4874                      instruction->cpu_flags = &flags->cpu_flags;
4875                      instruction->fpu_flags = &flags->fpu_flags;
4876                  }
4877  
4878  #endif
4879  
4880                  return ZYAN_STATUS_SUCCESS;
4881              }
4882              ZYAN_UNREACHABLE;
4883          }
4884          ZYAN_CHECK(status);
4885          node = ZydisDecoderTreeGetChildNode(node, index);
4886      } while ((node_type != ZYDIS_NODETYPE_INVALID) && !(node_type & ZYDIS_NODETYPE_DEFINITION_MASK));
4887      return ZYAN_STATUS_SUCCESS;
4888  }
4889  
4890  /* ---------------------------------------------------------------------------------------------- */
4891  
4892  /* ============================================================================================== */
4893  /* Exported functions                                                                             */
4894  /* ============================================================================================== */
4895  
4896  ZyanStatus ZydisDecoderInit(ZydisDecoder* decoder, ZydisMachineMode machine_mode,
4897      ZydisStackWidth stack_width)
4898  {
4899      static const ZyanBool decoder_modes[ZYDIS_DECODER_MODE_MAX_VALUE + 1] =
4900      {
4901  #ifdef ZYDIS_MINIMAL_MODE
4902          ZYAN_TRUE , // ZYDIS_DECODER_MODE_MINIMAL
4903  #else
4904          ZYAN_FALSE, // ZYDIS_DECODER_MODE_MINIMAL
4905  #endif
4906          ZYAN_FALSE, // ZYDIS_DECODER_MODE_AMD_BRANCHES
4907          ZYAN_FALSE, // ZYDIS_DECODER_MODE_KNC
4908          ZYAN_TRUE , // ZYDIS_DECODER_MODE_MPX
4909          ZYAN_TRUE , // ZYDIS_DECODER_MODE_CET
4910          ZYAN_TRUE , // ZYDIS_DECODER_MODE_LZCNT
4911          ZYAN_TRUE , // ZYDIS_DECODER_MODE_TZCNT
4912          ZYAN_FALSE, // ZYDIS_DECODER_MODE_WBNOINVD
4913          ZYAN_TRUE   // ZYDIS_DECODER_MODE_CLDEMOTE
4914      };
4915  
4916      if (!decoder)
4917      {
4918          return ZYAN_STATUS_INVALID_ARGUMENT;
4919      }
4920      switch (machine_mode)
4921      {
4922      case ZYDIS_MACHINE_MODE_LONG_64:
4923          if (stack_width != ZYDIS_STACK_WIDTH_64)
4924          {
4925              return ZYAN_STATUS_INVALID_ARGUMENT;
4926          }
4927          break;
4928      case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
4929      case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
4930      case ZYDIS_MACHINE_MODE_LEGACY_32:
4931      case ZYDIS_MACHINE_MODE_LEGACY_16:
4932      case ZYDIS_MACHINE_MODE_REAL_16:
4933          if ((stack_width != ZYDIS_STACK_WIDTH_16) && (stack_width != ZYDIS_STACK_WIDTH_32))
4934          {
4935              return ZYAN_STATUS_INVALID_ARGUMENT;
4936          }
4937          break;
4938      default:
4939          return ZYAN_STATUS_INVALID_ARGUMENT;
4940      }
4941  
4942      decoder->machine_mode = machine_mode;
4943      decoder->stack_width = stack_width;
4944      ZYAN_MEMCPY(&decoder->decoder_mode, &decoder_modes, sizeof(decoder_modes));
4945  
4946      return ZYAN_STATUS_SUCCESS;
4947  }
4948  
4949  ZyanStatus ZydisDecoderEnableMode(ZydisDecoder* decoder, ZydisDecoderMode mode, ZyanBool enabled)
4950  {
4951      if (!decoder || ((ZyanUSize)mode > ZYDIS_DECODER_MODE_MAX_VALUE))
4952      {
4953          return ZYAN_STATUS_INVALID_ARGUMENT;
4954      }
4955  
4956  #ifdef ZYDIS_MINIMAL_MODE
4957      if ((mode == ZYDIS_DECODER_MODE_MINIMAL) && !enabled)
4958      {
4959          return ZYAN_STATUS_INVALID_OPERATION;
4960      }
4961  #endif
4962  
4963      decoder->decoder_mode[mode] = enabled;
4964  
4965      return ZYAN_STATUS_SUCCESS;
4966  }
4967  
4968  ZyanStatus ZydisDecoderDecodeFull(const ZydisDecoder* decoder,
4969      const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction,
4970      ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT])
4971  {
4972      if (!decoder || !instruction || !buffer || !operands)
4973      {
4974          return ZYAN_STATUS_INVALID_ARGUMENT;
4975      }
4976      if (!length)
4977      {
4978          return ZYDIS_STATUS_NO_MORE_DATA;
4979      }
4980      if (decoder->decoder_mode[ZYDIS_DECODER_MODE_MINIMAL])
4981      {
4982          return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
4983      }
4984  
4985      ZydisDecoderContext context;
4986      ZYAN_CHECK(ZydisDecoderDecodeInstruction(decoder, &context, buffer, length, instruction));
4987      ZYAN_CHECK(ZydisDecoderDecodeOperands(decoder, &context, instruction, operands,
4988          instruction->operand_count));
4989      ZYAN_MEMSET(&operands[instruction->operand_count], 0,
4990          (ZYDIS_MAX_OPERAND_COUNT - instruction->operand_count) * sizeof(operands[0]));
4991  
4992      return ZYAN_STATUS_SUCCESS;
4993  }
4994  
4995  ZyanStatus ZydisDecoderDecodeInstruction(const ZydisDecoder* decoder, ZydisDecoderContext* context,
4996      const void* buffer, ZyanUSize length, ZydisDecodedInstruction* instruction)
4997  {
4998      if (!decoder || !instruction || !buffer)
4999      {
5000          return ZYAN_STATUS_INVALID_ARGUMENT;
5001      }
5002  
5003      if (!length)
5004      {
5005          return ZYDIS_STATUS_NO_MORE_DATA;
5006      }
5007  
5008      ZydisDecoderState state;
5009      ZYAN_MEMSET(&state, 0, sizeof(state));
5010      state.decoder = decoder;
5011      state.buffer = (const ZyanU8*)buffer;
5012      state.buffer_len = length;
5013      state.prefixes.offset_notrack = -1;
5014  
5015      ZydisDecoderContext default_context;
5016      if (!context)
5017      {
5018          // Use a fallback context if no custom one has been provided
5019          context = &default_context;
5020      }
5021      ZYAN_MEMSET(context, 0, sizeof(*context));
5022      state.context = context;
5023  
5024      ZYAN_MEMSET(instruction, 0, sizeof(*instruction));
5025      instruction->machine_mode = decoder->machine_mode;
5026      instruction->stack_width = 16 << decoder->stack_width;
5027  
5028      ZYAN_CHECK(ZydisCollectOptionalPrefixes(&state, instruction));
5029      ZYAN_CHECK(ZydisDecodeInstruction(&state, instruction));
5030  
5031      instruction->raw.encoding2 = instruction->encoding;
5032  
5033      return ZYAN_STATUS_SUCCESS;
5034  }
5035  
5036  ZyanStatus ZydisDecoderDecodeOperands(const ZydisDecoder* decoder,
5037      const ZydisDecoderContext* context, const ZydisDecodedInstruction* instruction,
5038      ZydisDecodedOperand* operands, ZyanU8 operand_count)
5039  {
5040  #ifdef ZYDIS_MINIMAL_MODE
5041  
5042      ZYAN_UNUSED(decoder);
5043      ZYAN_UNUSED(context);
5044      ZYAN_UNUSED(instruction);
5045      ZYAN_UNUSED(operands);
5046      ZYAN_UNUSED(operand_count);
5047  
5048      return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
5049  
5050  #else
5051  
5052      if (!decoder || !context || !context->definition || !instruction ||
5053          (operand_count && !operands) || (operand_count > ZYDIS_MAX_OPERAND_COUNT))
5054      {
5055          return ZYAN_STATUS_INVALID_ARGUMENT;
5056      }
5057  
5058      if (decoder->decoder_mode[ZYDIS_DECODER_MODE_MINIMAL])
5059      {
5060          return ZYAN_STATUS_MISSING_DEPENDENCY; // TODO: Introduce better status code
5061      }
5062  
5063      operand_count = ZYAN_MIN(operand_count, instruction->operand_count);
5064      if (!operand_count)
5065      {
5066          return ZYAN_STATUS_SUCCESS;
5067      }
5068  
5069      return ZydisDecodeOperands(decoder, context, instruction, operands, operand_count);
5070  
5071  #endif
5072  }
5073  
5074  /* ============================================================================================== */