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/Zydis/Register.h"
28 
29 /* ============================================================================================== */
30 /* Register strings                                                                               */
31 /* ============================================================================================== */
32 
33 #include "zydis/Zydis/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