1 
2 /* Testing framework, for developing code to copy vex's x87 simulation
3    state to and from a real x87 state image (the 108-byte thing).
4 
5    Includes code from fp_80_64.c.
6 */
7 
8 #include "../pub/libvex_basictypes.h"
9 #include "../pub/libvex_ir.h"
10 #include "../priv/guest-x86/gdefs.h"
11 #include <stdio.h>
12 #include <assert.h>
13 #include <stdlib.h>
14 
15 /* Get definitions of convert_f64le_to_f80le and
16    convert_f80le_to_f64le. */
17 #define USED_AS_INCLUDE
18 #include "fp_80_64.c"
19 #undef  USED_AS_INCLUDE
20 
21 
22 ////////////////////////////////////////////////////////////////
23 
24 /* Layout of the real x87 state. */
25 
26 typedef
27    struct {
28       UShort env[14];
29       UChar  reg[80];
30    }
31    Fpu_State;
32 
33 /* Offsets, in 16-bit ints, into the FPU environment (env) area. */
34 #define FP_ENV_CTRL   0
35 #define FP_ENV_STAT   2
36 #define FP_ENV_TAG    4
37 #define FP_ENV_IP     6 /* and 7 */
38 #define FP_ENV_CS     8
39 #define FP_ENV_OPOFF  10 /* and 11 */
40 #define FP_ENV_OPSEL  12
41 #define FP_REG(ii)    (10*(7-(ii)))
42 
43 
44 /* Layout of vex's FP state is defined in ../priv/guest-x86/gdefs.h */
45 
x87_to_vex(UChar * x87_state,UChar * vex_state)46 static void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
47 {
48    Int        r;
49    UInt       tag;
50    Double*    vexRegs = (Double*)(vex_state + OFFB_F0);
51    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
52    Fpu_State* x87     = (Fpu_State*)x87_state;
53    UInt       ftop    = (x87->env[FP_ENV_STAT] >> 11) & 7;
54    UInt       tagw    = x87->env[FP_ENV_TAG];
55 
56    /* Copy registers and tags */
57    for (r = 0; r < 8; r++) {
58       tag = (tagw >> (2*r)) & 3;
59       if (tag == 3) {
60          /* register is empty */
61          vexRegs[r] = 0.0;
62          vexTags[r] = 0;
63       } else {
64          /* register is non-empty */
65          convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] );
66          vexTags[r] = 1;
67       }
68    }
69 
70    /* stack pointer */
71    *(UInt*)(vex_state + OFFB_FTOP) = ftop;
72 
73    /* TODO: Check the CW is 037F.  Or at least, bottom 6 bits are 1
74       (all exceptions masked), and 11:10, which is rounding control,
75       is set to ..?
76    */
77 }
78 
79 
vex_to_x87(UChar * vex_state,UChar * x87_state)80 static void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
81 {
82    Int        i, r;
83    UInt       tagw;
84    Double*    vexRegs = (Double*)(vex_state + OFFB_F0);
85    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
86    Fpu_State* x87     = (Fpu_State*)x87_state;
87    UInt       ftop    = *(UInt*)(vex_state + OFFB_FTOP);
88 
89    for (i = 0; i < 14; i++)
90       x87->env[i] = 0;
91 
92    x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF;
93    x87->env[FP_ENV_CTRL] = 0x037F;
94    x87->env[FP_ENV_STAT] = (ftop & 7) << 11;
95 
96    tagw = 0;
97    for (r = 0; r < 8; r++) {
98       if (vexTags[r] == 0) {
99          /* register is empty */
100          tagw |= (3 << (2*r));
101          convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] );
102       } else {
103          /* register is full. */
104          tagw |= (0 << (2*r));
105          convert_f64le_to_f80le( (UChar*)&vexRegs[r],  &x87->reg[FP_REG(r)] );
106       }
107    }
108    x87->env[FP_ENV_TAG] = tagw;
109 }
110 
111 ////////////////////////////////////////////////////////////////
112 
113 // fwds ...
114 static void printFpuState ( UChar* fpu_state );
115 static void printVexState ( UChar* vex_state );
116 
117 
118 /* Capture the FPU state.  Convert it to vex.  Convert it back
119    to x87.  Print it at all stages.
120 */
capture_convert_show(UChar * x87_state0,UChar * x87_state1,UChar * vex_state)121 void capture_convert_show ( /* preallocated storage */
122                             UChar* x87_state0,
123                             UChar* x87_state1,
124                             UChar* vex_state )
125 {
126    asm volatile ("fsave (%0)"
127                  :
128                  : "r" (x87_state0)
129                  : "memory" );
130    x87_to_vex(x87_state0, vex_state);
131    vex_to_x87(vex_state, x87_state1);
132    printf("\n\n=================================================\n\n");
133    printFpuState(x87_state0);
134    printf("\n\n");
135    printVexState(vex_state);
136    printf("\n\n");
137 #if 0
138    asm volatile("frstor (%0) ; fsave (%0)"
139                  :
140                  : "r" (x87_state1)
141                  : "memory" );
142 #endif
143    printFpuState(x87_state1);
144    printf("\n\n");
145    x87_to_vex(x87_state1, vex_state);
146    printVexState(vex_state);
147    printf("\n\n");
148 }
149 
main(void)150 int main ( void )
151 {
152   UChar*  x87_state0 = malloc(sizeof(Fpu_State));
153   UChar* x87_state1 = malloc(sizeof(Fpu_State));
154   UChar* vex_state = malloc(1000);
155   asm volatile ("finit");
156   capture_convert_show(x87_state0, x87_state1, vex_state);
157   asm volatile ("fldpi");
158   capture_convert_show(x87_state0, x87_state1, vex_state);
159   asm volatile ("fldz ; fld1 ; fdiv %st(1)");
160   asm volatile ("fldln2 ; fldlg2 ; fchs ; fsqrt");
161   capture_convert_show(x87_state0, x87_state1, vex_state);
162   return 1;
163 }
164 
165 ////////////////////////////////////////////////////////////////
166 
167 /* Bitfield offsets for exceptions in the FPU status and control words. */
168 #define FP_E_INVAL    0
169 #define FP_E_DENOR    1
170 #define FP_E_DIVZ     2
171 #define FP_E_OVERF    3
172 #define FP_E_UNDER    4
173 #define FP_E_LOS      5
174 
175 /* More bitfield offsets, but for the status word only. */
176 #define FP_E_STACKF   6
177 #define FP_E_SUMMARY  7
178 #define FP_F_C0       8
179 #define FP_F_C1       9
180 #define FP_F_C2      10
181 #define FP_F_C3      14
182 /* top-of-stack ptr is bits 13,12,11 of the word */
183 #define FP_F_TOS_LO  11
184 #define FP_F_TOS_HI  13
185 
186 /* Register tags. */
187 #define FP_TAG_VALID 0
188 #define FP_TAG_ZERO  1
189 #define FP_TAG_SPEC  2
190 #define FP_TAG_EMPTY 3
191 
192 char* fp_tag_names[4]
193    = { "Valid", "Zero", "Spec", "Empty" };
194 
195 char* fp_exception_names[6]
196    = { "INVAL", "DENOR", "DIVZ", "OVERF", "UNDERF", "LOS" };
197 
198 
fp_get_tos(Fpu_State * x87)199 UInt fp_get_tos ( Fpu_State* x87 )
200 {
201    return (x87->env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7;
202 }
203 
fp_get_tag(Fpu_State * x87,UInt regno)204 UInt fp_get_tag ( Fpu_State* x87, UInt regno )
205 {
206    assert(!(regno < 0 || regno > 7));
207    return (x87->env[FP_ENV_TAG] >> (2*regno)) & 3;
208 }
209 
fp_get_statusword_flag(Fpu_State * x87,UInt flagno)210 UInt fp_get_statusword_flag ( Fpu_State* x87, UInt flagno )
211 {
212    assert(!(flagno < 0 || flagno > 15));
213    return (x87->env[FP_ENV_STAT] >> flagno) & 0x1;
214 }
215 
fp_get_controlword_flag(Fpu_State * x87,UInt flagno)216 UInt fp_get_controlword_flag ( Fpu_State* x87, UInt flagno )
217 {
218    assert(!(flagno < 0 || flagno > 15));
219    return (x87->env[FP_ENV_CTRL] >> flagno) & 0x1;
220 }
221 
222 
printFpuState(UChar * fpu_state)223 static void printFpuState ( UChar* fpu_state )
224 {
225    Fpu_State* x87 = (Fpu_State*)fpu_state;
226 
227    Int i, j, k;
228    assert(sizeof(Fpu_State)==108);
229    for (i = 7; i >= 0; i--) {
230       printf ( " %s fpreg%d: 0x",
231                (UInt)i == fp_get_tos(x87) ? "**" : "  ", i );
232       for (k = 0, j = FP_REG(i)+9; k < 10; k++,j--)
233          printf ( "%02x", (UInt)x87->reg[j]);
234       printf ( "  %5s  ", fp_tag_names[fp_get_tag(x87,i)] );
235       printf("\n");
236       //printf ( "%20.16e\n", fp_get_reg(i) );
237    }
238    printf("     fctrl:     0x%04x  masked: ",
239           (UInt)x87->env[FP_ENV_CTRL] );
240    for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
241       if (fp_get_controlword_flag(x87,i))
242          printf ( "%s ", fp_exception_names[i] );
243    printf ( "\n" );
244 
245    printf("     fstat:     0x%04x  except:",
246           (UInt)x87->env[FP_ENV_STAT] );
247    for (i = FP_E_INVAL; i <= FP_E_LOS; i++)
248       if (fp_get_statusword_flag(x87,i))
249          printf ( "%s ", fp_exception_names[i] );
250    printf ( "  top: %d  ", fp_get_tos(x87) );
251    printf ( "c3210: %d%d%d%d",
252             fp_get_statusword_flag(x87,FP_F_C3),
253             fp_get_statusword_flag(x87,FP_F_C2),
254             fp_get_statusword_flag(x87,FP_F_C1),
255             fp_get_statusword_flag(x87,FP_F_C0) );
256    printf ( "  STACKF: %d\n", fp_get_statusword_flag(x87,FP_E_STACKF) );
257 
258    printf("      ftag:     0x%04x  ", (UInt)x87->env[FP_ENV_TAG] );
259    for (i = 7; i >= 0; i--)
260       printf ( "%d:%s ", i, fp_tag_names[fp_get_tag(x87,i)] );
261    printf("\n");
262 
263    printf("       fip: 0x%08x\n",
264            (((UInt)x87->env[FP_ENV_IP+1]) << 16) |
265             ((UInt)x87->env[FP_ENV_IP]) );
266    printf("       fcs:     0x%04x\n",
267            ((UInt)x87->env[FP_ENV_CS]) );
268    printf("    fopoff: 0x%08x\n",
269            (((UInt)x87->env[FP_ENV_OPOFF+1]) << 16) |
270             ((UInt)x87->env[FP_ENV_OPOFF]) );
271    printf("    fopsel:     0x%04x\n",
272            ((UInt)x87->env[FP_ENV_OPSEL]) );
273 }
274 
275 
printVexState(UChar * vex_state)276 static void printVexState ( UChar* vex_state )
277 {
278    Int r;
279    ULong*     vexRegs = (ULong*)(vex_state + OFFB_F0);
280    UChar*     vexTags = (UChar*)(vex_state + OFFB_FTAG0);
281    UInt       ftop    = *(UInt*)(vex_state + OFFB_FTOP);
282 
283    for (r = 7; r >= 0; r--) {
284       printf("%s %%f%d:  0x%llx  %s\n",
285               r == ftop ? "##" : "  ",
286               r,
287               vexRegs[r],
288 	      vexTags[r] == 0 ? "Empty" : "Full" );
289    }
290 
291 }
292