/* Testing framework, for developing code to copy vex's x87 simulation state to and from a real x87 state image (the 108-byte thing). Includes code from fp_80_64.c. */ #include "../pub/libvex_basictypes.h" #include "../pub/libvex_ir.h" #include "../priv/guest-x86/gdefs.h" #include #include #include /* Get definitions of convert_f64le_to_f80le and convert_f80le_to_f64le. */ #define USED_AS_INCLUDE #include "fp_80_64.c" #undef USED_AS_INCLUDE //////////////////////////////////////////////////////////////// /* Layout of the real x87 state. */ typedef struct { UShort env[14]; UChar reg[80]; } Fpu_State; /* Offsets, in 16-bit ints, into the FPU environment (env) area. */ #define FP_ENV_CTRL 0 #define FP_ENV_STAT 2 #define FP_ENV_TAG 4 #define FP_ENV_IP 6 /* and 7 */ #define FP_ENV_CS 8 #define FP_ENV_OPOFF 10 /* and 11 */ #define FP_ENV_OPSEL 12 #define FP_REG(ii) (10*(7-(ii))) /* Layout of vex's FP state is defined in ../priv/guest-x86/gdefs.h */ static void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state ) { Int r; UInt tag; Double* vexRegs = (Double*)(vex_state + OFFB_F0); UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0); Fpu_State* x87 = (Fpu_State*)x87_state; UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7; UInt tagw = x87->env[FP_ENV_TAG]; /* Copy registers and tags */ for (r = 0; r < 8; r++) { tag = (tagw >> (2*r)) & 3; if (tag == 3) { /* register is empty */ vexRegs[r] = 0.0; vexTags[r] = 0; } else { /* register is non-empty */ convert_f80le_to_f64le( &x87->reg[FP_REG(r)], (UChar*)&vexRegs[r] ); vexTags[r] = 1; } } /* stack pointer */ *(UInt*)(vex_state + OFFB_FTOP) = ftop; /* TODO: Check the CW is 037F. Or at least, bottom 6 bits are 1 (all exceptions masked), and 11:10, which is rounding control, is set to ..? */ } static void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state ) { Int i, r; UInt tagw; Double* vexRegs = (Double*)(vex_state + OFFB_F0); UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0); Fpu_State* x87 = (Fpu_State*)x87_state; UInt ftop = *(UInt*)(vex_state + OFFB_FTOP); for (i = 0; i < 14; i++) x87->env[i] = 0; x87->env[1] = x87->env[3] = x87->env[5] = x87->env[13] = 0xFFFF; x87->env[FP_ENV_CTRL] = 0x037F; x87->env[FP_ENV_STAT] = (ftop & 7) << 11; tagw = 0; for (r = 0; r < 8; r++) { if (vexTags[r] == 0) { /* register is empty */ tagw |= (3 << (2*r)); convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] ); } else { /* register is full. */ tagw |= (0 << (2*r)); convert_f64le_to_f80le( (UChar*)&vexRegs[r], &x87->reg[FP_REG(r)] ); } } x87->env[FP_ENV_TAG] = tagw; } //////////////////////////////////////////////////////////////// // fwds ... static void printFpuState ( UChar* fpu_state ); static void printVexState ( UChar* vex_state ); /* Capture the FPU state. Convert it to vex. Convert it back to x87. Print it at all stages. */ void capture_convert_show ( /* preallocated storage */ UChar* x87_state0, UChar* x87_state1, UChar* vex_state ) { asm volatile ("fsave (%0)" : : "r" (x87_state0) : "memory" ); x87_to_vex(x87_state0, vex_state); vex_to_x87(vex_state, x87_state1); printf("\n\n=================================================\n\n"); printFpuState(x87_state0); printf("\n\n"); printVexState(vex_state); printf("\n\n"); #if 0 asm volatile("frstor (%0) ; fsave (%0)" : : "r" (x87_state1) : "memory" ); #endif printFpuState(x87_state1); printf("\n\n"); x87_to_vex(x87_state1, vex_state); printVexState(vex_state); printf("\n\n"); } int main ( void ) { UChar* x87_state0 = malloc(sizeof(Fpu_State)); UChar* x87_state1 = malloc(sizeof(Fpu_State)); UChar* vex_state = malloc(1000); asm volatile ("finit"); capture_convert_show(x87_state0, x87_state1, vex_state); asm volatile ("fldpi"); capture_convert_show(x87_state0, x87_state1, vex_state); asm volatile ("fldz ; fld1 ; fdiv %st(1)"); asm volatile ("fldln2 ; fldlg2 ; fchs ; fsqrt"); capture_convert_show(x87_state0, x87_state1, vex_state); return 1; } //////////////////////////////////////////////////////////////// /* Bitfield offsets for exceptions in the FPU status and control words. */ #define FP_E_INVAL 0 #define FP_E_DENOR 1 #define FP_E_DIVZ 2 #define FP_E_OVERF 3 #define FP_E_UNDER 4 #define FP_E_LOS 5 /* More bitfield offsets, but for the status word only. */ #define FP_E_STACKF 6 #define FP_E_SUMMARY 7 #define FP_F_C0 8 #define FP_F_C1 9 #define FP_F_C2 10 #define FP_F_C3 14 /* top-of-stack ptr is bits 13,12,11 of the word */ #define FP_F_TOS_LO 11 #define FP_F_TOS_HI 13 /* Register tags. */ #define FP_TAG_VALID 0 #define FP_TAG_ZERO 1 #define FP_TAG_SPEC 2 #define FP_TAG_EMPTY 3 char* fp_tag_names[4] = { "Valid", "Zero", "Spec", "Empty" }; char* fp_exception_names[6] = { "INVAL", "DENOR", "DIVZ", "OVERF", "UNDERF", "LOS" }; UInt fp_get_tos ( Fpu_State* x87 ) { return (x87->env[FP_ENV_STAT] >> FP_F_TOS_LO) & 7; } UInt fp_get_tag ( Fpu_State* x87, UInt regno ) { assert(!(regno < 0 || regno > 7)); return (x87->env[FP_ENV_TAG] >> (2*regno)) & 3; } UInt fp_get_statusword_flag ( Fpu_State* x87, UInt flagno ) { assert(!(flagno < 0 || flagno > 15)); return (x87->env[FP_ENV_STAT] >> flagno) & 0x1; } UInt fp_get_controlword_flag ( Fpu_State* x87, UInt flagno ) { assert(!(flagno < 0 || flagno > 15)); return (x87->env[FP_ENV_CTRL] >> flagno) & 0x1; } static void printFpuState ( UChar* fpu_state ) { Fpu_State* x87 = (Fpu_State*)fpu_state; Int i, j, k; assert(sizeof(Fpu_State)==108); for (i = 7; i >= 0; i--) { printf ( " %s fpreg%d: 0x", (UInt)i == fp_get_tos(x87) ? "**" : " ", i ); for (k = 0, j = FP_REG(i)+9; k < 10; k++,j--) printf ( "%02x", (UInt)x87->reg[j]); printf ( " %5s ", fp_tag_names[fp_get_tag(x87,i)] ); printf("\n"); //printf ( "%20.16e\n", fp_get_reg(i) ); } printf(" fctrl: 0x%04x masked: ", (UInt)x87->env[FP_ENV_CTRL] ); for (i = FP_E_INVAL; i <= FP_E_LOS; i++) if (fp_get_controlword_flag(x87,i)) printf ( "%s ", fp_exception_names[i] ); printf ( "\n" ); printf(" fstat: 0x%04x except:", (UInt)x87->env[FP_ENV_STAT] ); for (i = FP_E_INVAL; i <= FP_E_LOS; i++) if (fp_get_statusword_flag(x87,i)) printf ( "%s ", fp_exception_names[i] ); printf ( " top: %d ", fp_get_tos(x87) ); printf ( "c3210: %d%d%d%d", fp_get_statusword_flag(x87,FP_F_C3), fp_get_statusword_flag(x87,FP_F_C2), fp_get_statusword_flag(x87,FP_F_C1), fp_get_statusword_flag(x87,FP_F_C0) ); printf ( " STACKF: %d\n", fp_get_statusword_flag(x87,FP_E_STACKF) ); printf(" ftag: 0x%04x ", (UInt)x87->env[FP_ENV_TAG] ); for (i = 7; i >= 0; i--) printf ( "%d:%s ", i, fp_tag_names[fp_get_tag(x87,i)] ); printf("\n"); printf(" fip: 0x%08x\n", (((UInt)x87->env[FP_ENV_IP+1]) << 16) | ((UInt)x87->env[FP_ENV_IP]) ); printf(" fcs: 0x%04x\n", ((UInt)x87->env[FP_ENV_CS]) ); printf(" fopoff: 0x%08x\n", (((UInt)x87->env[FP_ENV_OPOFF+1]) << 16) | ((UInt)x87->env[FP_ENV_OPOFF]) ); printf(" fopsel: 0x%04x\n", ((UInt)x87->env[FP_ENV_OPSEL]) ); } static void printVexState ( UChar* vex_state ) { Int r; ULong* vexRegs = (ULong*)(vex_state + OFFB_F0); UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0); UInt ftop = *(UInt*)(vex_state + OFFB_FTOP); for (r = 7; r >= 0; r--) { printf("%s %%f%d: 0x%llx %s\n", r == ftop ? "##" : " ", r, vexRegs[r], vexTags[r] == 0 ? "Empty" : "Full" ); } }