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 * @brief Defines the `ZydisRegisterMapItem` struct.
41 */
42 typedef struct ZydisRegisterMapItem_
43 {
44 /**
45 * @brief The register class.
46 */
47 ZydisRegisterClass class;
48 /**
49 * @brief The lowest register of the current class.
50 */
51 ZydisRegister lo;
52 /**
53 * @brief The highest register of the current class.
54 */
55 ZydisRegister hi;
56 /**
57 * @brief The width of registers of the current class in 16- and 32-bit mode.
58 */
59 ZydisRegisterWidth width;
60 /**
61 * @brief The width of registers of the current class in 64-bit mode.
62 */
63 ZydisRegisterWidth width64;
64 } ZydisRegisterMapItem;
65
66 /**
67 * @brief Provides register to register-class and register-class + id to register mappings.
68 */
69 static const ZydisRegisterMapItem REGISTER_MAP[] =
70 {
71 { ZYDIS_REGCLASS_INVALID , ZYDIS_REGISTER_NONE , ZYDIS_REGISTER_NONE , 0 , 0 },
72 { ZYDIS_REGCLASS_GPR8 , ZYDIS_REGISTER_AL , ZYDIS_REGISTER_R15B , 8 , 8 },
73 { ZYDIS_REGCLASS_GPR16 , ZYDIS_REGISTER_AX , ZYDIS_REGISTER_R15W , 16 , 16 },
74 { ZYDIS_REGCLASS_GPR32 , ZYDIS_REGISTER_EAX , ZYDIS_REGISTER_R15D , 32 , 32 },
75 { ZYDIS_REGCLASS_GPR64 , ZYDIS_REGISTER_RAX , ZYDIS_REGISTER_R15 , 0 , 64 },
76 { ZYDIS_REGCLASS_X87 , ZYDIS_REGISTER_ST0 , ZYDIS_REGISTER_ST7 , 80 , 80 },
77 { ZYDIS_REGCLASS_MMX , ZYDIS_REGISTER_MM0 , ZYDIS_REGISTER_MM7 , 64 , 64 },
78 { ZYDIS_REGCLASS_XMM , ZYDIS_REGISTER_XMM0 , ZYDIS_REGISTER_XMM31 , 128 , 128 },
79 { ZYDIS_REGCLASS_YMM , ZYDIS_REGISTER_YMM0 , ZYDIS_REGISTER_YMM31 , 256 , 256 },
80 { ZYDIS_REGCLASS_ZMM , ZYDIS_REGISTER_ZMM0 , ZYDIS_REGISTER_ZMM31 , 512 , 512 },
81 { ZYDIS_REGCLASS_FLAGS , ZYDIS_REGISTER_FLAGS , ZYDIS_REGISTER_RFLAGS , 0 , 0 },
82 { ZYDIS_REGCLASS_IP , ZYDIS_REGISTER_IP , ZYDIS_REGISTER_RIP , 0 , 0 },
83 { ZYDIS_REGCLASS_SEGMENT , ZYDIS_REGISTER_ES , ZYDIS_REGISTER_GS , 16 , 16 },
84 { ZYDIS_REGCLASS_TEST , ZYDIS_REGISTER_TR0 , ZYDIS_REGISTER_TR7 , 32 , 32 },
85 { ZYDIS_REGCLASS_CONTROL , ZYDIS_REGISTER_CR0 , ZYDIS_REGISTER_CR15 , 32 , 64 },
86 { ZYDIS_REGCLASS_DEBUG , ZYDIS_REGISTER_DR0 , ZYDIS_REGISTER_DR15 , 32 , 64 },
87 { ZYDIS_REGCLASS_MASK , ZYDIS_REGISTER_K0 , ZYDIS_REGISTER_K7 , 0 , 0 },
88 { ZYDIS_REGCLASS_BOUND , ZYDIS_REGISTER_BND0 , ZYDIS_REGISTER_BND3 , 128 , 128 }
89 };
90
91 /* ============================================================================================== */
92 /* Exported functions */
93 /* ============================================================================================== */
94
95 /* ---------------------------------------------------------------------------------------------- */
96 /* Register */
97 /* ---------------------------------------------------------------------------------------------- */
98
ZydisRegisterEncode(ZydisRegisterClass register_class,ZyanU8 id)99 ZydisRegister ZydisRegisterEncode(ZydisRegisterClass register_class, ZyanU8 id)
100 {
101 switch (register_class)
102 {
103 case ZYDIS_REGCLASS_INVALID:
104 case ZYDIS_REGCLASS_FLAGS:
105 case ZYDIS_REGCLASS_IP:
106 break;
107 default:
108 if (((ZyanUSize)register_class < ZYAN_ARRAY_LENGTH(REGISTER_MAP)) &&
109 (id <= (REGISTER_MAP[register_class].hi - REGISTER_MAP[register_class].lo)))
110 {
111 return REGISTER_MAP[register_class].lo + id;
112 }
113 }
114 return ZYDIS_REGISTER_NONE;
115 }
116
ZydisRegisterGetId(ZydisRegister reg)117 ZyanI8 ZydisRegisterGetId(ZydisRegister reg)
118 {
119 for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(REGISTER_MAP); ++i)
120 {
121 switch (REGISTER_MAP[i].class)
122 {
123 case ZYDIS_REGCLASS_INVALID:
124 case ZYDIS_REGCLASS_FLAGS:
125 case ZYDIS_REGCLASS_IP:
126 break;
127 default:
128 if ((reg >= REGISTER_MAP[i].lo) && (reg <= REGISTER_MAP[i].hi))
129 {
130 return (ZyanU8)(reg - REGISTER_MAP[i].lo);
131 }
132 }
133 }
134 return -1;
135 }
136
ZydisRegisterGetClass(ZydisRegister reg)137 ZydisRegisterClass ZydisRegisterGetClass(ZydisRegister reg)
138 {
139 for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(REGISTER_MAP); ++i)
140 {
141 if ((reg >= REGISTER_MAP[i].lo) && (reg <= REGISTER_MAP[i].hi))
142 {
143 return REGISTER_MAP[i].class;
144 }
145 }
146 return ZYDIS_REGCLASS_INVALID;
147 }
148
ZydisRegisterGetWidth(ZydisMachineMode mode,ZydisRegister reg)149 ZydisRegisterWidth ZydisRegisterGetWidth(ZydisMachineMode mode, ZydisRegister reg)
150 {
151 // Special cases
152 switch (reg)
153 {
154 case ZYDIS_REGISTER_X87CONTROL:
155 case ZYDIS_REGISTER_X87STATUS:
156 case ZYDIS_REGISTER_X87TAG:
157 return 16;
158 case ZYDIS_REGISTER_IP:
159 case ZYDIS_REGISTER_FLAGS:
160 return 16;
161 case ZYDIS_REGISTER_EIP:
162 case ZYDIS_REGISTER_EFLAGS:
163 return 32;
164 case ZYDIS_REGISTER_RIP:
165 case ZYDIS_REGISTER_RFLAGS:
166 return (mode == ZYDIS_MACHINE_MODE_LONG_64) ? 64 : 0;
167 case ZYDIS_REGISTER_BNDCFG:
168 case ZYDIS_REGISTER_BNDSTATUS:
169 return 64;
170 case ZYDIS_REGISTER_XCR0:
171 return 64;
172 case ZYDIS_REGISTER_PKRU:
173 case ZYDIS_REGISTER_MXCSR:
174 return 32;
175 default:
176 break;
177 }
178
179 // Register classes
180 for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(REGISTER_MAP); ++i)
181 {
182 if ((reg >= REGISTER_MAP[i].lo) && (reg <= REGISTER_MAP[i].hi))
183 {
184 return (mode == ZYDIS_MACHINE_MODE_LONG_64) ?
185 REGISTER_MAP[i].width64 : REGISTER_MAP[i].width;
186 }
187 }
188 return 0;
189 }
190
ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode,ZydisRegister reg)191 ZydisRegister ZydisRegisterGetLargestEnclosing(ZydisMachineMode mode,
192 ZydisRegister reg)
193 {
194 static const ZyanU8 GPR8_MAPPING[20] =
195 {
196 /* AL */ 0,
197 /* CL */ 1,
198 /* DL */ 2,
199 /* BL */ 3,
200 /* AH */ 0,
201 /* CH */ 1,
202 /* DH */ 2,
203 /* BH */ 3,
204 /* SPL */ 4,
205 /* BPL */ 5,
206 /* SIL */ 6,
207 /* DIL */ 7,
208 /* R8B */ 8,
209 /* R9B */ 9,
210 /* R10B */ 10,
211 /* R11B */ 11,
212 /* R12B */ 12,
213 /* R13B */ 13,
214 /* R14B */ 14,
215 /* R15B */ 15,
216 };
217
218 for (ZyanUSize i = 0; i < ZYAN_ARRAY_LENGTH(REGISTER_MAP); ++i)
219 {
220 if ((reg >= REGISTER_MAP[i].lo) && (reg <= REGISTER_MAP[i].hi))
221 {
222 const ZydisRegisterClass reg_class = REGISTER_MAP[i].class;
223 if ((reg_class == ZYDIS_REGCLASS_GPR64) && (mode != ZYDIS_MACHINE_MODE_LONG_64))
224 {
225 return ZYDIS_REGISTER_NONE;
226 }
227
228 ZyanU8 reg_id = (ZyanU8)(reg - REGISTER_MAP[reg_class].lo);
229 switch (reg_class)
230 {
231 case ZYDIS_REGCLASS_GPR8:
232 reg_id = GPR8_MAPPING[reg_id];
233 ZYAN_FALLTHROUGH;
234 case ZYDIS_REGCLASS_GPR16:
235 case ZYDIS_REGCLASS_GPR32:
236 case ZYDIS_REGCLASS_GPR64:
237 switch (mode)
238 {
239 case ZYDIS_MACHINE_MODE_LONG_64:
240 return REGISTER_MAP[ZYDIS_REGCLASS_GPR64].lo + reg_id;
241 case ZYDIS_MACHINE_MODE_LONG_COMPAT_32:
242 case ZYDIS_MACHINE_MODE_LEGACY_32:
243 return REGISTER_MAP[ZYDIS_REGCLASS_GPR32].lo + reg_id;
244 case ZYDIS_MACHINE_MODE_LONG_COMPAT_16:
245 case ZYDIS_MACHINE_MODE_LEGACY_16:
246 case ZYDIS_MACHINE_MODE_REAL_16:
247 return REGISTER_MAP[ZYDIS_REGCLASS_GPR16].lo + reg_id;
248 default:
249 return ZYDIS_REGISTER_NONE;
250 }
251 case ZYDIS_REGCLASS_XMM:
252 case ZYDIS_REGCLASS_YMM:
253 case ZYDIS_REGCLASS_ZMM:
254 #if defined(ZYDIS_DISABLE_AVX512) && defined(ZYDIS_DISABLE_KNC)
255 return REGISTER_MAP[ZYDIS_REGCLASS_YMM].lo + reg_id;
256 #else
257 return REGISTER_MAP[ZYDIS_REGCLASS_ZMM].lo + reg_id;
258 #endif
259 default:
260 return ZYDIS_REGISTER_NONE;
261 }
262 }
263 }
264
265 return ZYDIS_REGISTER_NONE;
266 }
267
ZydisRegisterGetString(ZydisRegister reg)268 const char* ZydisRegisterGetString(ZydisRegister reg)
269 {
270 if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTER))
271 {
272 return ZYAN_NULL;
273 }
274 return STR_REGISTER[reg].data;
275 }
276
ZydisRegisterGetStringWrapped(ZydisRegister reg)277 const ZydisShortString* ZydisRegisterGetStringWrapped(ZydisRegister reg)
278 {
279 if ((ZyanUSize)reg >= ZYAN_ARRAY_LENGTH(STR_REGISTER))
280 {
281 return ZYAN_NULL;
282 }
283 return &STR_REGISTER[reg];
284 }
285
286 /* ---------------------------------------------------------------------------------------------- */
287 /* Register class */
288 /* ---------------------------------------------------------------------------------------------- */
289
ZydisRegisterClassGetWidth(ZydisMachineMode mode,ZydisRegisterClass register_class)290 ZydisRegisterWidth ZydisRegisterClassGetWidth(ZydisMachineMode mode,
291 ZydisRegisterClass register_class)
292 {
293 if ((ZyanUSize)register_class < ZYAN_ARRAY_LENGTH(REGISTER_MAP))
294 {
295 return (mode == ZYDIS_MACHINE_MODE_LONG_64) ?
296 REGISTER_MAP[register_class].width64 : REGISTER_MAP[register_class].width;
297 }
298 return 0;
299 }
300
301 /* ---------------------------------------------------------------------------------------------- */
302
303 /* ============================================================================================== */
304