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 = ®_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