/ externals / zydis / src / Register.c
Register.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  #include <Zydis/Register.h>
 28  
 29  /* ============================================================================================== */
 30  /* Register strings                                                                               */
 31  /* ============================================================================================== */
 32  
 33  #include <Generated/EnumRegister.inc>
 34  
 35  /* ============================================================================================== */
 36  /* Register-class mapping                                                                         */
 37  /* ============================================================================================== */
 38  
 39  /**
 40   * Defines the `ZydisRegisterMapItem` struct.
 41   */
 42  typedef struct ZydisRegisterLookupItem
 43  {
 44      /**
 45       * The register class.
 46       */
 47      ZydisRegisterClass class;
 48      /**
 49       * The register id.
 50       */
 51      ZyanI8 id;
 52      /**
 53       * The width of register 16- and 32-bit mode.
 54       */
 55      ZydisRegisterWidth width;
 56      /**
 57       * The width of register in 64-bit mode.
 58       */
 59      ZydisRegisterWidth width64;
 60  } ZydisRegisterLookupItem;
 61  
 62  #include <Generated/RegisterLookup.inc>
 63  
 64  /**
 65   * Defines the `ZydisRegisterClassLookupItem` struct.
 66   */
 67  typedef struct ZydisRegisterClassLookupItem_
 68  {
 69      /**
 70       * The lowest register of the current class.
 71       */
 72      ZydisRegister lo;
 73      /**
 74       * The highest register of the current class.
 75       */
 76      ZydisRegister hi;
 77      /**
 78       * The width of registers of the current class in 16- and 32-bit mode.
 79       */
 80      ZydisRegisterWidth width;
 81      /**
 82       * The width of registers of the current class in 64-bit mode.
 83       */
 84      ZydisRegisterWidth width64;
 85  } ZydisRegisterClassLookupItem;
 86  
 87  #include <Generated/RegisterClassLookup.inc>
 88  
 89  /* ============================================================================================== */
 90  /* Exported functions                                                                             */
 91  /* ============================================================================================== */
 92  
 93  /* ---------------------------------------------------------------------------------------------- */
 94  /* Register                                                                                       */
 95  /* ---------------------------------------------------------------------------------------------- */
 96  
 97  ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id)
 98  {
 99      if ((register_class == ZYDIS_REGCLASS_INVALID) ||
100          (register_class == ZYDIS_REGCLASS_FLAGS) ||
101          (register_class == ZYDIS_REGCLASS_IP))
102      {
103          return ZYDIS_REGISTER_NONE;
104      }
105  
106      if ((ZyanUSize)register_class >= ZYAN_ARRAY_LENGTH(REG_CLASS_LOOKUP))
107      {
108          return ZYDIS_REGISTER_NONE;
109      }
110  
111      const ZydisRegisterClassLookupItem* item = &REG_CLASS_LOOKUP[register_class];
112      if (id <= (item->hi - item->lo))
113      {
114          return item->lo + id;
115      }
116  
117      return ZYDIS_REGISTER_NONE;
118  }
119  
120  ZyanI8 ZydisRegisterGetId(ZydisRegister reg)
121  {
122      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(REG_LOOKUP))
123      {
124          return -1;
125      }
126  
127      return REG_LOOKUP[reg].id;
128  }
129  
130  ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg)
131  {
132      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(REG_LOOKUP))
133      {
134          return ZYDIS_REGCLASS_INVALID;
135      }
136  
137      return REG_LOOKUP[reg].class;
138  }
139  
140  ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg)
141  {
142      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(REG_LOOKUP))
143      {
144          return 0;
145      }
146  
147      return (mode == ZYDIS_MACHINE_MODE_LONG_64)
148          ? REG_LOOKUP[reg].width64
149          : REG_LOOKUP[reg].width;
150  }
151  
152  ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode, ZydisRegister reg)
153  {
154      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(REG_LOOKUP))
155      {
156          return ZYDIS_REGISTER_NONE;
157      }
158  
159      static const ZyanU8 GPR8_MAPPING[20] =
160      {
161          /* AL   */  0,
162          /* CL   */  1,
163          /* DL   */  2,
164          /* BL   */  3,
165          /* AH   */  0,
166          /* CH   */  1,
167          /* DH   */  2,
168          /* BH   */  3,
169          /* SPL  */  4,
170          /* BPL  */  5,
171          /* SIL  */  6,
172          /* DIL  */  7,
173          /* R8B  */  8,
174          /* R9B  */  9,
175          /* R10B */ 10,
176          /* R11B */ 11,
177          /* R12B */ 12,
178          /* R13B */ 13,
179          /* R14B */ 14,
180          /* R15B */ 15,
181      };
182  
183      const ZydisRegisterClass reg_class = REG_LOOKUP[reg].class;
184      if ((reg_class == ZYDIS_REGCLASS_INVALID) ||
185          ((reg_class == ZYDIS_REGCLASS_GPR64) && (mode != ZYDIS_MACHINE_MODE_LONG_64)))
186      {
187          return ZYDIS_REGISTER_NONE;
188      }
189  
190      ZyanU8 reg_id = REG_LOOKUP[reg].id;
191      switch (reg_class)
192      {
193      case ZYDIS_REGCLASS_GPR8:
194          reg_id = GPR8_MAPPING[reg_id];
195          ZYAN_FALLTHROUGH;
196      case ZYDIS_REGCLASS_GPR16:
197      case ZYDIS_REGCLASS_GPR32:
198      case ZYDIS_REGCLASS_GPR64:
199          switch (mode)
200          {
201          case ZYDIS_MACHINE_MODE_LONG_64:
202              return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR64].lo + reg_id;
203          case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
204          case ZYDIS_MACHINE_MODE_LEGACY_32:
205              return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR32].lo + reg_id;
206          case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
207          case ZYDIS_MACHINE_MODE_LEGACY_16:
208          case ZYDIS_MACHINE_MODE_REAL_16:
209              return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR16].lo + reg_id;
210          default:
211              return ZYDIS_REGISTER_NONE;
212          }
213      case ZYDIS_REGCLASS_XMM:
214      case ZYDIS_REGCLASS_YMM:
215      case ZYDIS_REGCLASS_ZMM:
216  #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
217          return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_YMM].lo + reg_id;
218  #else
219          return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_ZMM].lo + reg_id;
220  #endif
221      default:
222          return ZYDIS_REGISTER_NONE;
223      }
224  }
225  
226  const char* ZydisRegisterGetString(ZydisRegister reg)
227  {
228      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTERS))
229      {
230          return ZYAN_NULL;
231      }
232  
233      return STR_REGISTERS[reg].data;
234  }
235  
236  const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg)
237  {
238      if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTERS))
239      {
240          return ZYAN_NULL;
241      }
242  
243      return &STR_REGISTERS[reg];
244  }
245  
246  /* ---------------------------------------------------------------------------------------------- */
247  /* Register class                                                                                 */
248  /* ---------------------------------------------------------------------------------------------- */
249  
250  ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode,
251      ZydisRegisterClass register_class)
252  {
253      if ((ZyanUSize)register_class >= ZYAN_ARRAY_LENGTH(REG_CLASS_LOOKUP))
254      {
255          return 0;
256      }
257  
258      return (mode == ZYDIS_MACHINE_MODE_LONG_64)
259          ? REG_CLASS_LOOKUP[register_class].width64
260          : REG_CLASS_LOOKUP[register_class].width;
261  }
262  
263  /* ---------------------------------------------------------------------------------------------- */
264  
265  /* ============================================================================================== */