xref: /haiku/src/libs/zydis/Zydis/Register.c (revision 1003e004e6c97eb60657a98928dd334e141c59ee)
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 
ZydisRegisterEncode(ZydisRegisterClass register_class,ZyanU8 id)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 
ZydisRegisterGetId(ZydisRegister reg)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 
ZydisRegisterGetClass(ZydisRegister reg)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 
ZydisRegisterGetWidth(ZydisMachineMode mode,ZydisRegister reg)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 
ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode,ZydisRegister reg)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     if (mode > ZYDIS_MACHINE_MODE_MAX_VALUE)
160     {
161         return ZYDIS_REGISTER_NONE;
162     }
163 
164     const ZydisRegisterClass reg_class = REG_LOOKUP[reg].class;
165 
166     if ((reg_class == ZYDIS_REGCLASS_INVALID) ||
167         ((reg_class == ZYDIS_REGCLASS_GPR64) && (mode != ZYDIS_MACHINE_MODE_LONG_64)))
168     {
169         return ZYDIS_REGISTER_NONE;
170     }
171 
172     static const ZydisRegister STATIC_MAPPING[ZYDIS_REGCLASS_MAX_VALUE + 1][3] =
173     {
174                                  /* 16              */ /* 32               */ /* 64                  */
175         [ZYDIS_REGCLASS_FLAGS] = { ZYDIS_REGISTER_FLAGS, ZYDIS_REGISTER_EFLAGS, ZYDIS_REGISTER_RFLAGS },
176         [ZYDIS_REGCLASS_IP   ] = { ZYDIS_REGISTER_IP   , ZYDIS_REGISTER_EIP   , ZYDIS_REGISTER_RIP    },
177     };
178     ZYAN_ASSERT(reg_class < ZYAN_ARRAY_LENGTH(STATIC_MAPPING));
179 
180     ZyanU8 mode_bits;
181     switch (mode)
182     {
183     case ZYDIS_MACHINE_MODE_LONG_64:
184         mode_bits = 2;
185         break;
186     case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
187     case ZYDIS_MACHINE_MODE_LEGACY_32:
188         mode_bits = 1;
189         break;
190     case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
191     case ZYDIS_MACHINE_MODE_LEGACY_16:
192     case ZYDIS_MACHINE_MODE_REAL_16:
193         mode_bits = 0;
194         break;
195     default:
196         ZYAN_UNREACHABLE;
197     }
198 
199     const ZydisRegister static_reg = STATIC_MAPPING[reg_class][mode_bits];
200     if (static_reg != ZYDIS_REGISTER_NONE)
201     {
202         return static_reg;
203     }
204 
205     static const ZyanU8 GPR8_MAPPING[20] =
206     {
207         /* AL   */  0,
208         /* CL   */  1,
209         /* DL   */  2,
210         /* BL   */  3,
211         /* AH   */  0,
212         /* CH   */  1,
213         /* DH   */  2,
214         /* BH   */  3,
215         /* SPL  */  4,
216         /* BPL  */  5,
217         /* SIL  */  6,
218         /* DIL  */  7,
219         /* R8B  */  8,
220         /* R9B  */  9,
221         /* R10B */ 10,
222         /* R11B */ 11,
223         /* R12B */ 12,
224         /* R13B */ 13,
225         /* R14B */ 14,
226         /* R15B */ 15
227     };
228 
229     ZyanU8 reg_id = REG_LOOKUP[reg].id;
230     switch (reg_class)
231     {
232     case ZYDIS_REGCLASS_GPR8:
233         reg_id = GPR8_MAPPING[reg_id];
234         ZYAN_FALLTHROUGH;
235     case ZYDIS_REGCLASS_GPR16:
236     case ZYDIS_REGCLASS_GPR32:
237     case ZYDIS_REGCLASS_GPR64:
238         switch (mode_bits)
239         {
240         case 2:
241             return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR64].lo + reg_id;
242         case 1:
243             return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR32].lo + reg_id;
244         case 0:
245             return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_GPR16].lo + reg_id;
246         default:
247             ZYAN_UNREACHABLE;
248         }
249     case ZYDIS_REGCLASS_XMM:
250     case ZYDIS_REGCLASS_YMM:
251     case ZYDIS_REGCLASS_ZMM:
252 #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
253         return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_YMM].lo + reg_id;
254 #else
255         return REG_CLASS_LOOKUP[ZYDIS_REGCLASS_ZMM].lo + reg_id;
256 #endif
257     default:
258         return ZYDIS_REGISTER_NONE;
259     }
260 }
261 
ZydisRegisterGetString(ZydisRegister reg)262 const char* ZydisRegisterGetString(ZydisRegister reg)
263 {
264     if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTERS))
265     {
266         return ZYAN_NULL;
267     }
268 
269     return STR_REGISTERS[reg].data;
270 }
271 
ZydisRegisterGetStringWrapped(ZydisRegister reg)272 const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg)
273 {
274     if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTERS))
275     {
276         return ZYAN_NULL;
277     }
278 
279     return &STR_REGISTERS[reg];
280 }
281 
282 /* ---------------------------------------------------------------------------------------------- */
283 /* Register class                                                                                 */
284 /* ---------------------------------------------------------------------------------------------- */
285 
ZydisRegisterClassGetWidth(ZydisMachineMode mode,ZydisRegisterClass register_class)286 ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode,
287     ZydisRegisterClass register_class)
288 {
289     if ((ZyanUSize)register_class >= ZYAN_ARRAY_LENGTH(REG_CLASS_LOOKUP))
290     {
291         return 0;
292     }
293 
294     return (mode == ZYDIS_MACHINE_MODE_LONG_64)
295         ? REG_CLASS_LOOKUP[register_class].width64
296         : REG_CLASS_LOOKUP[register_class].width;
297 }
298 
299 /* ---------------------------------------------------------------------------------------------- */
300 
301 /* ============================================================================================== */
302