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 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 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 */ 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 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 199 UInt fp_get_tos ( Fpu_State* x87 ) 200 { 201 return (x87->env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7; 202 } 203 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 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 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 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 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