mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-13 06:33:56 +00:00
Remove all references to hardwired guest state offsets. Instead,
allow definition of a struct containing the guest state (eg, VexGuestX86State in pub/libvex_guest_x86.h) and derive all offsets from that struct. git-svn-id: svn://svn.valgrind.org/vex/trunk@365
This commit is contained in:
@@ -144,99 +144,6 @@ typedef
|
||||
}
|
||||
Condcode;
|
||||
|
||||
|
||||
/*---------------------------------------------------------*/
|
||||
/*--- Simulated state offsets ---*/
|
||||
/*---------------------------------------------------------*/
|
||||
|
||||
/* Hmm, subregisters. The simulated state is stored in memory in the
|
||||
host's byte ordering, so we can't say here what the offsets of %ax,
|
||||
%al, %ah etc are since that depends on the host's byte ordering,
|
||||
which we don't know. */
|
||||
|
||||
#define OFFB_EAX (0*4)
|
||||
#define OFFB_ECX (1*4)
|
||||
#define OFFB_EDX (2*4)
|
||||
#define OFFB_EBX (3*4)
|
||||
#define OFFB_ESP (4*4)
|
||||
#define OFFB_EBP (5*4)
|
||||
#define OFFB_ESI (6*4)
|
||||
#define OFFB_EDI (7*4)
|
||||
/* 3-word thunk used to calculate O S Z A C P flags. */
|
||||
#define OFFB_CC_OP (8*4)
|
||||
#define OFFB_CC_SRC (9*4)
|
||||
#define OFFB_CC_DST (10*4)
|
||||
/* The D flag is stored here, as either -1 or +1 */
|
||||
#define OFFB_DFLAG (11*4)
|
||||
/* EIP */
|
||||
#define OFFB_EIP (12*4)
|
||||
|
||||
/* FPU. For now, just simulate 8 64-bit registers, their tags, and
|
||||
the reg-stack top pointer, of which only the least significant
|
||||
three bits are relevant.
|
||||
|
||||
The model is:
|
||||
F0 .. F7 are the 8 registers. FTOP[2:0] contains the
|
||||
index of the current 'stack top' -- pretty meaningless, but
|
||||
still. FTOP is a 32-bit value. FTOP[31:3] can be anything
|
||||
(not guaranteed to be zero).
|
||||
|
||||
When a value is pushed onto the stack, ftop is first replaced by
|
||||
(ftop-1) & 7, and then F[ftop] is assigned the value.
|
||||
|
||||
When a value is popped off the stack, the value is read from
|
||||
F[ftop], and then ftop is replaced by (ftop+1) & 7.
|
||||
|
||||
In general, a reference to a register ST(i) actually references
|
||||
F[ (ftop+i) & 7 ].
|
||||
|
||||
FTAG0 .. FTAG0+7 are the tags. Each is a byte, zero means empty,
|
||||
non-zero means non-empty.
|
||||
|
||||
The general rule appears to be that a read or modify of a register
|
||||
gets a stack underflow fault if the register is empty. A write of
|
||||
a register (only a write, not a modify) gets a stack overflow fault
|
||||
if the register is full. Note that "over" vs "under" is pretty
|
||||
meaningless since the FP stack pointer can move around arbitrarily,
|
||||
so it's really just two different kinds of exceptions:
|
||||
register-empty and register full.
|
||||
|
||||
Naturally Intel (in its infinite wisdom) has seen fit to throw in
|
||||
some ad-hoc inconsistencies to the fault-generation rules of the
|
||||
above para, just to complicate everything. Known inconsistencies:
|
||||
|
||||
* fxam can read a register in any state without taking an underflow
|
||||
fault.
|
||||
|
||||
* fst from st(0) to st(i) does not take an overflow fault even if the
|
||||
destination is already full.
|
||||
|
||||
FPUCW[15:0] is the FPU's control word. FPUCW[31:16] is unused.
|
||||
|
||||
FC3210 contains the C3, C2, C1 and C0 bits in the same place they
|
||||
are in the FPU's status word. (bits 14, 10, 9, 8 respectively).
|
||||
All other bits should be zero. The relevant mask to select just
|
||||
those bits is 0x4700. To select C3, C2 and C0 only, the mask is
|
||||
0x4500.
|
||||
*/
|
||||
#define OFFB_FTOP (13*4)
|
||||
#define OFFB_F0 (14*4)
|
||||
#define OFFB_F1 (16*4)
|
||||
#define OFFB_F2 (18*4)
|
||||
#define OFFB_F3 (20*4)
|
||||
#define OFFB_F4 (22*4)
|
||||
#define OFFB_F5 (24*4)
|
||||
#define OFFB_F6 (26*4)
|
||||
#define OFFB_F7 (28*4)
|
||||
#define OFFB_FTAG0 (30*4) // up to 30*4 + 7
|
||||
#define OFFB_FPUCW (32*4)
|
||||
#define OFFB_FC3210 (33*4)
|
||||
|
||||
/* Don't forget to keep this up to date. */
|
||||
#define SIZEOF_X86H_STATE (OFFB_FC3210 + 4)
|
||||
|
||||
|
||||
|
||||
#endif /* ndef __LIBVEX_X86GUEST_DEFS_H */
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
@@ -1218,12 +1218,13 @@ typedef
|
||||
|
||||
|
||||
/* VISIBLE TO LIBVEX CLIENT */
|
||||
void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
|
||||
void x87_to_vex ( /*IN*/UChar* x87_state,
|
||||
/*OUT*/VexGuestX86State* vex_state )
|
||||
{
|
||||
Int r;
|
||||
UInt tag;
|
||||
Double* vexRegs = (Double*)(vex_state + OFFB_F0);
|
||||
UChar* vexTags = (UChar*)(vex_state + OFFB_FTAG0);
|
||||
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
|
||||
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
|
||||
Fpu_State* x87 = (Fpu_State*)x87_state;
|
||||
UInt ftop = (x87->env[FP_ENV_STAT] >> 11) & 7;
|
||||
UInt tagw = x87->env[FP_ENV_TAG];
|
||||
@@ -1245,32 +1246,33 @@ void x87_to_vex ( /*IN*/UChar* x87_state, /*OUT*/UChar* vex_state )
|
||||
}
|
||||
|
||||
/* stack pointer */
|
||||
*(UInt*)(vex_state + OFFB_FTOP) = ftop;
|
||||
vex_state->guest_FTOP = ftop;
|
||||
|
||||
/* control word */
|
||||
*(UInt*)(vex_state + OFFB_FPUCW) = fpucw;
|
||||
vex_state->guest_FPUCW = fpucw;
|
||||
|
||||
/* status word */
|
||||
*(UInt*)(vex_state + OFFB_FC3210) = c3210;
|
||||
vex_state->guest_FC3210 = c3210;
|
||||
}
|
||||
|
||||
|
||||
/* VISIBLE TO LIBVEX CLIENT */
|
||||
void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
|
||||
void vex_to_x87 ( /*IN*/VexGuestX86State* 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);
|
||||
Double* vexRegs = (Double*)(&vex_state->guest_FPREG[0]);
|
||||
UChar* vexTags = (UChar*)(&vex_state->guest_FPTAG[0]);
|
||||
Fpu_State* x87 = (Fpu_State*)x87_state;
|
||||
UInt ftop = *(UInt*)(vex_state + OFFB_FTOP);
|
||||
UInt c3210 = *(UInt*)(vex_state + OFFB_FC3210);
|
||||
UInt ftop = vex_state->guest_FTOP;
|
||||
UInt c3210 = vex_state->guest_FC3210;
|
||||
|
||||
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] = (UShort)( *(UInt*)(vex_state + OFFB_FPUCW) );
|
||||
x87->env[FP_ENV_CTRL] = (UShort)( vex_state->guest_FPUCW );
|
||||
x87->env[FP_ENV_STAT] = ((ftop & 7) << 11) | (c3210 & 0x4700);
|
||||
|
||||
tagw = 0;
|
||||
@@ -1289,6 +1291,42 @@ void vex_to_x87 ( /*IN*/UChar* vex_state, /*OUT*/UChar* x87_state )
|
||||
}
|
||||
|
||||
|
||||
/* VISIBLE TO LIBVEX CLIENT */
|
||||
void eflags_to_vex ( UInt eflags_native,
|
||||
/*OUT*/VexGuestX86State* vex_state )
|
||||
{
|
||||
vex_state->guest_DFLAG
|
||||
= (eflags_native & (1<<10)) ? 0xFFFFFFFF : 0x00000001;
|
||||
|
||||
/* Mask out everything except O S Z A C P. */
|
||||
eflags_native
|
||||
&= (CC_MASK_C | CC_MASK_P | CC_MASK_A
|
||||
| CC_MASK_Z | CC_MASK_S | CC_MASK_O);
|
||||
|
||||
vex_state->guest_CC_OP = CC_OP_COPY;
|
||||
vex_state->guest_CC_DST = 0;
|
||||
vex_state->guest_CC_DST = eflags_native;
|
||||
}
|
||||
|
||||
|
||||
/* VISIBLE TO LIBVEX CLIENT */
|
||||
UInt vex_to_eflags ( /*IN*/VexGuestX86State* vex_state )
|
||||
{
|
||||
UInt eflags = calculate_eflags_all(
|
||||
vex_state->guest_CC_OP,
|
||||
vex_state->guest_CC_SRC,
|
||||
vex_state->guest_CC_DST
|
||||
);
|
||||
UInt dflag = vex_state->guest_DFLAG;
|
||||
vassert(dflag == 1 || dflag == 0xFFFFFFFF);
|
||||
if (dflag == 0xFFFFFFFF)
|
||||
eflags |= (1<<10);
|
||||
|
||||
return eflags;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
/*--- end guest-x86/ghelpers.c ---*/
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "libvex_basictypes.h"
|
||||
#include "libvex_ir.h"
|
||||
#include "libvex.h"
|
||||
#include "libvex_guest_x86.h"
|
||||
|
||||
#include "main/vex_util.h"
|
||||
#include "main/vex_globals.h"
|
||||
@@ -198,6 +199,24 @@ IRBB* bbToIR_X86Instr ( UChar* x86code,
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Offsets of various parts of the x86 guest state. ---*/
|
||||
/*------------------------------------------------------------*/
|
||||
|
||||
#define offsetof(type,memb) ((Int)&((type*)0)->memb)
|
||||
|
||||
#define OFFB_FPREGS offsetof(VexGuestX86State,guest_FPREG[0])
|
||||
#define OFFB_FPTAGS offsetof(VexGuestX86State,guest_FPTAG[0])
|
||||
#define OFFB_EAX offsetof(VexGuestX86State,guest_EAX)
|
||||
#define OFFB_CC_OP offsetof(VexGuestX86State,guest_CC_OP)
|
||||
#define OFFB_CC_SRC offsetof(VexGuestX86State,guest_CC_SRC)
|
||||
#define OFFB_CC_DST offsetof(VexGuestX86State,guest_CC_DST)
|
||||
#define OFFB_DFLAG offsetof(VexGuestX86State,guest_DFLAG)
|
||||
#define OFFB_FTOP offsetof(VexGuestX86State,guest_FTOP)
|
||||
#define OFFB_FC3210 offsetof(VexGuestX86State,guest_FC3210)
|
||||
#define OFFB_FPUCW offsetof(VexGuestX86State,guest_FPUCW)
|
||||
|
||||
|
||||
/*------------------------------------------------------------*/
|
||||
/*--- Helper bits and pieces for deconstructing the ---*/
|
||||
/*--- x86 insn stream. ---*/
|
||||
@@ -3217,7 +3236,7 @@ static void put_ST_TAG ( Int i, IRExpr* value )
|
||||
{
|
||||
IRArray* descr;
|
||||
vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_I8);
|
||||
descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
|
||||
descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
|
||||
stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
|
||||
}
|
||||
|
||||
@@ -3226,7 +3245,7 @@ static void put_ST_TAG ( Int i, IRExpr* value )
|
||||
|
||||
static IRExpr* get_ST_TAG ( Int i )
|
||||
{
|
||||
IRArray* descr = mkIRArray( OFFB_FTAG0, Ity_I8, 8 );
|
||||
IRArray* descr = mkIRArray( OFFB_FPTAGS, Ity_I8, 8 );
|
||||
return IRExpr_GetI( descr, get_ftop(), i );
|
||||
}
|
||||
|
||||
@@ -3241,7 +3260,7 @@ static void put_ST_UNCHECKED ( Int i, IRExpr* value )
|
||||
{
|
||||
IRArray* descr;
|
||||
vassert(typeOfIRExpr(irbb->tyenv, value) == Ity_F64);
|
||||
descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
|
||||
descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
|
||||
stmt( IRStmt_PutI( descr, get_ftop(), i, value ) );
|
||||
/* Mark the register as in-use. */
|
||||
put_ST_TAG(i, mkU8(1));
|
||||
@@ -3269,7 +3288,7 @@ static void put_ST ( Int i, IRExpr* value )
|
||||
|
||||
static IRExpr* get_ST_UNCHECKED ( Int i )
|
||||
{
|
||||
IRArray* descr = mkIRArray( OFFB_F0, Ity_F64, 8 );
|
||||
IRArray* descr = mkIRArray( OFFB_FPREGS, Ity_F64, 8 );
|
||||
return IRExpr_GetI( descr, get_ftop(), i );
|
||||
}
|
||||
|
||||
|
||||
@@ -11,19 +11,127 @@
|
||||
|
||||
#include "libvex_basictypes.h"
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
/*--- Vex's representation of the x86 CPU state. ---*/
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
/* The integer parts should be pretty straightforward. */
|
||||
|
||||
/* Hmm, subregisters. The simulated state is stored in memory in the
|
||||
host's byte ordering, so we can't say here what the offsets of %ax,
|
||||
%al, %ah etc are since that depends on the host's byte ordering,
|
||||
which we don't know. */
|
||||
|
||||
/* FPU. For now, just simulate 8 64-bit registers, their tags, and
|
||||
the reg-stack top pointer, of which only the least significant
|
||||
three bits are relevant.
|
||||
|
||||
The model is:
|
||||
F0 .. F7 are the 8 registers. FTOP[2:0] contains the
|
||||
index of the current 'stack top' -- pretty meaningless, but
|
||||
still. FTOP is a 32-bit value. FTOP[31:3] can be anything
|
||||
(not guaranteed to be zero).
|
||||
|
||||
When a value is pushed onto the stack, ftop is first replaced by
|
||||
(ftop-1) & 7, and then F[ftop] is assigned the value.
|
||||
|
||||
When a value is popped off the stack, the value is read from
|
||||
F[ftop], and then ftop is replaced by (ftop+1) & 7.
|
||||
|
||||
In general, a reference to a register ST(i) actually references
|
||||
F[ (ftop+i) & 7 ].
|
||||
|
||||
FTAG0 .. FTAG0+7 are the tags. Each is a byte, zero means empty,
|
||||
non-zero means non-empty.
|
||||
|
||||
The general rule appears to be that a read or modify of a register
|
||||
gets a stack underflow fault if the register is empty. A write of
|
||||
a register (only a write, not a modify) gets a stack overflow fault
|
||||
if the register is full. Note that "over" vs "under" is pretty
|
||||
meaningless since the FP stack pointer can move around arbitrarily,
|
||||
so it's really just two different kinds of exceptions:
|
||||
register-empty and register full.
|
||||
|
||||
Naturally Intel (in its infinite wisdom) has seen fit to throw in
|
||||
some ad-hoc inconsistencies to the fault-generation rules of the
|
||||
above para, just to complicate everything. Known inconsistencies:
|
||||
|
||||
* fxam can read a register in any state without taking an underflow
|
||||
fault.
|
||||
|
||||
* fst from st(0) to st(i) does not take an overflow fault even if the
|
||||
destination is already full.
|
||||
|
||||
FPUCW[15:0] is the FPU's control word. FPUCW[31:16] is unused.
|
||||
|
||||
FC3210 contains the C3, C2, C1 and C0 bits in the same place they
|
||||
are in the FPU's status word. (bits 14, 10, 9, 8 respectively).
|
||||
All other bits should be zero. The relevant mask to select just
|
||||
those bits is 0x4700. To select C3, C2 and C0 only, the mask is
|
||||
0x4500.
|
||||
*/
|
||||
|
||||
typedef
|
||||
struct {
|
||||
UInt guest_EAX;
|
||||
UInt guest_ECX;
|
||||
UInt guest_EDX;
|
||||
UInt guest_EBX;
|
||||
UInt guest_ESP;
|
||||
UInt guest_EBP;
|
||||
UInt guest_ESI;
|
||||
UInt guest_EDI;
|
||||
/* 3-word thunk used to calculate O S Z A C P flags. */
|
||||
UInt guest_CC_OP;
|
||||
UInt guest_CC_SRC;
|
||||
UInt guest_CC_DST;
|
||||
/* The D flag is stored here, as either -1 or +1 */
|
||||
UInt guest_DFLAG;
|
||||
/* EIP */
|
||||
UInt guest_EIP;
|
||||
/* FPU */
|
||||
UInt guest_FTOP;
|
||||
ULong guest_FPREG[8];
|
||||
UChar guest_FPTAG[8];
|
||||
UInt guest_FPUCW;
|
||||
UInt guest_FC3210;
|
||||
}
|
||||
VexGuestX86State;
|
||||
|
||||
|
||||
/*---------------------------------------------------------------*/
|
||||
/*--- Utility functions for x86 guest stuff. ---*/
|
||||
/*---------------------------------------------------------------*/
|
||||
|
||||
/* Convert a saved x87 FPU image (as created by fsave) into the
|
||||
equivalent vex representation.
|
||||
/* Convert a saved x87 FPU image (as created by fsave) and write it
|
||||
into the supplied VexGuestX86State structure. The non-FP parts of
|
||||
said structure are left unchanged.
|
||||
*/
|
||||
extern void x87_to_vex ( /*IN*/UChar* x87_state,
|
||||
/*OUT*/UChar* vex_state );
|
||||
extern
|
||||
void x87_to_vex ( /*IN*/UChar* x87_state,
|
||||
/*OUT*/VexGuestX86State* vex_state );
|
||||
|
||||
/* Extract from the supplied VexGuestX86State structure, an x87 FPU
|
||||
image. */
|
||||
extern
|
||||
void vex_to_x87 ( /*IN*/VexGuestX86State* vex_state,
|
||||
/*OUT*/UChar* x87_state );
|
||||
|
||||
|
||||
/* Given a 32-bit word containing native x86 %eflags values, set the
|
||||
eflag-related fields in the supplied VexGuestX86State accordingly.
|
||||
All other fields are left unchanged. */
|
||||
|
||||
extern
|
||||
void eflags_to_vex ( UInt eflags_native,
|
||||
/*OUT*/VexGuestX86State* vex_state );
|
||||
|
||||
/* Extract from the supplied VexGuestX86State structure the
|
||||
corresponding native %eflags value. */
|
||||
|
||||
extern
|
||||
UInt vex_to_eflags ( /*IN*/VexGuestX86State* vex_state );
|
||||
|
||||
/* Extract from the vex representation, an x87 FPU image. */
|
||||
extern void vex_to_x87 ( /*IN*/UChar* vex_state,
|
||||
/*OUT*/UChar* x87_state );
|
||||
|
||||
#endif /* ndef __LIBVEX_PUB_GUEST_X86_H */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user