|
1 #include <stdlib.h> |
|
2 #include <string.h> |
|
3 |
|
4 #include "ia32_reg.h" |
|
5 #include "ia32_insn.h" |
|
6 |
|
7 #define NUM_X86_REGS 92 |
|
8 |
|
9 /* register sizes */ |
|
10 #define REG_DWORD_SIZE 4 |
|
11 #define REG_WORD_SIZE 2 |
|
12 #define REG_BYTE_SIZE 1 |
|
13 #define REG_MMX_SIZE 8 |
|
14 #define REG_SIMD_SIZE 16 |
|
15 #define REG_DEBUG_SIZE 4 |
|
16 #define REG_CTRL_SIZE 4 |
|
17 #define REG_TEST_SIZE 4 |
|
18 #define REG_SEG_SIZE 2 |
|
19 #define REG_FPU_SIZE 10 |
|
20 #define REG_FLAGS_SIZE 4 |
|
21 #define REG_FPCTRL_SIZE 2 |
|
22 #define REG_FPSTATUS_SIZE 2 |
|
23 #define REG_FPTAG_SIZE 2 |
|
24 #define REG_EIP_SIZE 4 |
|
25 #define REG_IP_SIZE 2 |
|
26 |
|
27 /* REGISTER ALIAS TABLE: |
|
28 * |
|
29 * NOTE: the MMX register mapping is fixed to the physical registers |
|
30 * used by the FPU. The floating FP stack does not effect the location |
|
31 * of the MMX registers, so this aliasing is not 100% accurate. |
|
32 * */ |
|
33 static struct { |
|
34 unsigned char alias; /* id of register this is an alias for */ |
|
35 unsigned char shift; /* # of bits register must be shifted */ |
|
36 } ia32_reg_aliases[] = { |
|
37 { 0,0 }, |
|
38 { REG_DWORD_OFFSET, 0 }, /* al : 1 */ |
|
39 { REG_DWORD_OFFSET, 8 }, /* ah : 2 */ |
|
40 { REG_DWORD_OFFSET, 0 }, /* ax : 3 */ |
|
41 { REG_DWORD_OFFSET + 1, 0 }, /* cl : 4 */ |
|
42 { REG_DWORD_OFFSET + 1, 8 }, /* ch : 5 */ |
|
43 { REG_DWORD_OFFSET + 1, 0 }, /* cx : 6 */ |
|
44 { REG_DWORD_OFFSET + 2, 0 }, /* dl : 7 */ |
|
45 { REG_DWORD_OFFSET + 2, 8 }, /* dh : 8 */ |
|
46 { REG_DWORD_OFFSET + 2, 0 }, /* dx : 9 */ |
|
47 { REG_DWORD_OFFSET + 3, 0 }, /* bl : 10 */ |
|
48 { REG_DWORD_OFFSET + 3, 8 }, /* bh : 11 */ |
|
49 { REG_DWORD_OFFSET + 3, 0 }, /* bx : 12 */ |
|
50 { REG_DWORD_OFFSET + 4, 0 }, /* sp : 13 */ |
|
51 { REG_DWORD_OFFSET + 5, 0 }, /* bp : 14 */ |
|
52 { REG_DWORD_OFFSET + 6, 0 }, /* si : 15 */ |
|
53 { REG_DWORD_OFFSET + 7, 0 }, /* di : 16 */ |
|
54 { REG_EIP_INDEX, 0 }, /* ip : 17 */ |
|
55 { REG_FPU_OFFSET, 0 }, /* mm0 : 18 */ |
|
56 { REG_FPU_OFFSET + 1, 0 }, /* mm1 : 19 */ |
|
57 { REG_FPU_OFFSET + 2, 0 }, /* mm2 : 20 */ |
|
58 { REG_FPU_OFFSET + 3, 0 }, /* mm3 : 21 */ |
|
59 { REG_FPU_OFFSET + 4, 0 }, /* mm4 : 22 */ |
|
60 { REG_FPU_OFFSET + 5, 0 }, /* mm5 : 23 */ |
|
61 { REG_FPU_OFFSET + 6, 0 }, /* mm6 : 24 */ |
|
62 { REG_FPU_OFFSET + 7, 0 } /* mm7 : 25 */ |
|
63 }; |
|
64 |
|
65 /* REGISTER TABLE: size, type, and name of every register in the |
|
66 * CPU. Does not include MSRs since the are, after all, |
|
67 * model specific. */ |
|
68 static struct { |
|
69 unsigned int size; |
|
70 enum x86_reg_type type; |
|
71 unsigned int alias; |
|
72 char mnemonic[8]; |
|
73 } ia32_reg_table[NUM_X86_REGS + 2] = { |
|
74 { 0, 0, 0, "" }, |
|
75 /* REG_DWORD_OFFSET */ |
|
76 { REG_DWORD_SIZE, reg_gen | reg_ret, 0, "eax" }, |
|
77 { REG_DWORD_SIZE, reg_gen | reg_count, 0, "ecx" }, |
|
78 { REG_DWORD_SIZE, reg_gen, 0, "edx" }, |
|
79 { REG_DWORD_SIZE, reg_gen, 0, "ebx" }, |
|
80 /* REG_ESP_INDEX */ |
|
81 { REG_DWORD_SIZE, reg_gen | reg_sp, 0, "esp" }, |
|
82 { REG_DWORD_SIZE, reg_gen | reg_fp, 0, "ebp" }, |
|
83 { REG_DWORD_SIZE, reg_gen | reg_src, 0, "esi" }, |
|
84 { REG_DWORD_SIZE, reg_gen | reg_dest, 0, "edi" }, |
|
85 /* REG_WORD_OFFSET */ |
|
86 { REG_WORD_SIZE, reg_gen | reg_ret, 3, "ax" }, |
|
87 { REG_WORD_SIZE, reg_gen | reg_count, 6, "cx" }, |
|
88 { REG_WORD_SIZE, reg_gen, 9, "dx" }, |
|
89 { REG_WORD_SIZE, reg_gen, 12, "bx" }, |
|
90 { REG_WORD_SIZE, reg_gen | reg_sp, 13, "sp" }, |
|
91 { REG_WORD_SIZE, reg_gen | reg_fp, 14, "bp" }, |
|
92 { REG_WORD_SIZE, reg_gen | reg_src, 15, "si" }, |
|
93 { REG_WORD_SIZE, reg_gen | reg_dest, 16, "di" }, |
|
94 /* REG_BYTE_OFFSET */ |
|
95 { REG_BYTE_SIZE, reg_gen, 1, "al" }, |
|
96 { REG_BYTE_SIZE, reg_gen, 4, "cl" }, |
|
97 { REG_BYTE_SIZE, reg_gen, 7, "dl" }, |
|
98 { REG_BYTE_SIZE, reg_gen, 10, "bl" }, |
|
99 { REG_BYTE_SIZE, reg_gen, 2, "ah" }, |
|
100 { REG_BYTE_SIZE, reg_gen, 5, "ch" }, |
|
101 { REG_BYTE_SIZE, reg_gen, 8, "dh" }, |
|
102 { REG_BYTE_SIZE, reg_gen, 11, "bh" }, |
|
103 /* REG_MMX_OFFSET */ |
|
104 { REG_MMX_SIZE, reg_simd, 18, "mm0" }, |
|
105 { REG_MMX_SIZE, reg_simd, 19, "mm1" }, |
|
106 { REG_MMX_SIZE, reg_simd, 20, "mm2" }, |
|
107 { REG_MMX_SIZE, reg_simd, 21, "mm3" }, |
|
108 { REG_MMX_SIZE, reg_simd, 22, "mm4" }, |
|
109 { REG_MMX_SIZE, reg_simd, 23, "mm5" }, |
|
110 { REG_MMX_SIZE, reg_simd, 24, "mm6" }, |
|
111 { REG_MMX_SIZE, reg_simd, 25, "mm7" }, |
|
112 /* REG_SIMD_OFFSET */ |
|
113 { REG_SIMD_SIZE, reg_simd, 0, "xmm0" }, |
|
114 { REG_SIMD_SIZE, reg_simd, 0, "xmm1" }, |
|
115 { REG_SIMD_SIZE, reg_simd, 0, "xmm2" }, |
|
116 { REG_SIMD_SIZE, reg_simd, 0, "xmm3" }, |
|
117 { REG_SIMD_SIZE, reg_simd, 0, "xmm4" }, |
|
118 { REG_SIMD_SIZE, reg_simd, 0, "xmm5" }, |
|
119 { REG_SIMD_SIZE, reg_simd, 0, "xmm6" }, |
|
120 { REG_SIMD_SIZE, reg_simd, 0, "xmm7" }, |
|
121 /* REG_DEBUG_OFFSET */ |
|
122 { REG_DEBUG_SIZE, reg_sys, 0, "dr0" }, |
|
123 { REG_DEBUG_SIZE, reg_sys, 0, "dr1" }, |
|
124 { REG_DEBUG_SIZE, reg_sys, 0, "dr2" }, |
|
125 { REG_DEBUG_SIZE, reg_sys, 0, "dr3" }, |
|
126 { REG_DEBUG_SIZE, reg_sys, 0, "dr4" }, |
|
127 { REG_DEBUG_SIZE, reg_sys, 0, "dr5" }, |
|
128 { REG_DEBUG_SIZE, reg_sys, 0, "dr6" }, |
|
129 { REG_DEBUG_SIZE, reg_sys, 0, "dr7" }, |
|
130 /* REG_CTRL_OFFSET */ |
|
131 { REG_CTRL_SIZE, reg_sys, 0, "cr0" }, |
|
132 { REG_CTRL_SIZE, reg_sys, 0, "cr1" }, |
|
133 { REG_CTRL_SIZE, reg_sys, 0, "cr2" }, |
|
134 { REG_CTRL_SIZE, reg_sys, 0, "cr3" }, |
|
135 { REG_CTRL_SIZE, reg_sys, 0, "cr4" }, |
|
136 { REG_CTRL_SIZE, reg_sys, 0, "cr5" }, |
|
137 { REG_CTRL_SIZE, reg_sys, 0, "cr6" }, |
|
138 { REG_CTRL_SIZE, reg_sys, 0, "cr7" }, |
|
139 /* REG_TEST_OFFSET */ |
|
140 { REG_TEST_SIZE, reg_sys, 0, "tr0" }, |
|
141 { REG_TEST_SIZE, reg_sys, 0, "tr1" }, |
|
142 { REG_TEST_SIZE, reg_sys, 0, "tr2" }, |
|
143 { REG_TEST_SIZE, reg_sys, 0, "tr3" }, |
|
144 { REG_TEST_SIZE, reg_sys, 0, "tr4" }, |
|
145 { REG_TEST_SIZE, reg_sys, 0, "tr5" }, |
|
146 { REG_TEST_SIZE, reg_sys, 0, "tr6" }, |
|
147 { REG_TEST_SIZE, reg_sys, 0, "tr7" }, |
|
148 /* REG_SEG_OFFSET */ |
|
149 { REG_SEG_SIZE, reg_seg, 0, "es" }, |
|
150 { REG_SEG_SIZE, reg_seg, 0, "cs" }, |
|
151 { REG_SEG_SIZE, reg_seg, 0, "ss" }, |
|
152 { REG_SEG_SIZE, reg_seg, 0, "ds" }, |
|
153 { REG_SEG_SIZE, reg_seg, 0, "fs" }, |
|
154 { REG_SEG_SIZE, reg_seg, 0, "gs" }, |
|
155 /* REG_LDTR_INDEX */ |
|
156 { REG_DWORD_SIZE, reg_sys, 0, "ldtr" }, |
|
157 /* REG_GDTR_INDEX */ |
|
158 { REG_DWORD_SIZE, reg_sys, 0, "gdtr" }, |
|
159 /* REG_FPU_OFFSET */ |
|
160 { REG_FPU_SIZE, reg_fpu, 0, "st(0)" }, |
|
161 { REG_FPU_SIZE, reg_fpu, 0, "st(1)" }, |
|
162 { REG_FPU_SIZE, reg_fpu, 0, "st(2)" }, |
|
163 { REG_FPU_SIZE, reg_fpu, 0, "st(3)" }, |
|
164 { REG_FPU_SIZE, reg_fpu, 0, "st(4)" }, |
|
165 { REG_FPU_SIZE, reg_fpu, 0, "st(5)" }, |
|
166 { REG_FPU_SIZE, reg_fpu, 0, "st(6)" }, |
|
167 { REG_FPU_SIZE, reg_fpu, 0, "st(7)" }, |
|
168 /* REG_FLAGS_INDEX : 81 */ |
|
169 { REG_FLAGS_SIZE, reg_cond, 0, "eflags" }, |
|
170 /* REG_FPCTRL_INDEX : 82*/ |
|
171 { REG_FPCTRL_SIZE, reg_fpu | reg_sys, 0, "fpctrl" }, |
|
172 /* REG_FPSTATUS_INDEX : 83*/ |
|
173 { REG_FPSTATUS_SIZE, reg_fpu | reg_sys, 0, "fpstat" }, |
|
174 /* REG_FPTAG_INDEX : 84 */ |
|
175 { REG_FPTAG_SIZE, reg_fpu | reg_sys, 0, "fptag" }, |
|
176 /* REG_EIP_INDEX : 85 */ |
|
177 { REG_EIP_SIZE, reg_pc, 0, "eip" }, |
|
178 /* REG_IP_INDEX : 86 */ |
|
179 { REG_IP_SIZE, reg_pc, 17, "ip" }, |
|
180 /* REG_IDTR_INDEX : 87 */ |
|
181 { REG_DWORD_SIZE, reg_sys, 0, "idtr" }, |
|
182 /* REG_MXCSG_INDEX : SSE Control Reg : 88 */ |
|
183 { REG_DWORD_SIZE, reg_sys | reg_simd, 0, "mxcsr" }, |
|
184 /* REG_TR_INDEX : Task Register : 89 */ |
|
185 { 16 + 64, reg_sys, 0, "tr" }, |
|
186 /* REG_CSMSR_INDEX : SYSENTER_CS_MSR : 90 */ |
|
187 { REG_DWORD_SIZE, reg_sys, 0, "cs_msr" }, |
|
188 /* REG_ESPMSR_INDEX : SYSENTER_ESP_MSR : 91 */ |
|
189 { REG_DWORD_SIZE, reg_sys, 0, "esp_msr" }, |
|
190 /* REG_EIPMSR_INDEX : SYSENTER_EIP_MSR : 92 */ |
|
191 { REG_DWORD_SIZE, reg_sys, 0, "eip_msr" }, |
|
192 { 0 } |
|
193 }; |
|
194 |
|
195 |
|
196 static size_t sz_regtable = NUM_X86_REGS + 1; |
|
197 |
|
198 |
|
199 void ia32_handle_register( x86_reg_t *reg, size_t id ) { |
|
200 unsigned int alias; |
|
201 if (! id || id > sz_regtable ) { |
|
202 return; |
|
203 } |
|
204 |
|
205 memset( reg, 0, sizeof(x86_reg_t) ); |
|
206 |
|
207 strncpy( reg->name, ia32_reg_table[id].mnemonic, MAX_REGNAME ); |
|
208 |
|
209 reg->type = ia32_reg_table[id].type; |
|
210 reg->size = ia32_reg_table[id].size; |
|
211 |
|
212 alias = ia32_reg_table[id].alias; |
|
213 if ( alias ) { |
|
214 reg->alias = ia32_reg_aliases[alias].alias; |
|
215 reg->shift = ia32_reg_aliases[alias].shift; |
|
216 } |
|
217 reg->id = id; |
|
218 |
|
219 return; |
|
220 } |
|
221 |
|
222 size_t ia32_true_register_id( size_t id ) { |
|
223 size_t reg; |
|
224 |
|
225 if (! id || id > sz_regtable ) { |
|
226 return 0; |
|
227 } |
|
228 |
|
229 reg = id; |
|
230 if (ia32_reg_table[reg].alias) { |
|
231 reg = ia32_reg_aliases[ia32_reg_table[reg].alias].alias; |
|
232 } |
|
233 return reg; |
|
234 } |