• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*---------------------------------------------------------------*/
3 /*--- begin                                libvex_guest_x86.h ---*/
4 /*---------------------------------------------------------------*/
5 
6 /*
7    This file is part of Valgrind, a dynamic binary instrumentation
8    framework.
9 
10    Copyright (C) 2004-2010 OpenWorks LLP
11       info@open-works.net
12 
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of the
16    License, or (at your option) any later version.
17 
18    This program is distributed in the hope that it will be useful, but
19    WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21    General Public License for more details.
22 
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26    02110-1301, USA.
27 
28    The GNU General Public License is contained in the file COPYING.
29 
30    Neither the names of the U.S. Department of Energy nor the
31    University of California nor the names of its contributors may be
32    used to endorse or promote products derived from this software
33    without prior written permission.
34 */
35 
36 #ifndef __LIBVEX_PUB_GUEST_X86_H
37 #define __LIBVEX_PUB_GUEST_X86_H
38 
39 #include "libvex_basictypes.h"
40 #include "libvex_emwarn.h"
41 
42 
43 /*---------------------------------------------------------------*/
44 /*--- Vex's representation of the x86 CPU state.              ---*/
45 /*---------------------------------------------------------------*/
46 
47 /* The integer parts should be pretty straightforward. */
48 
49 /* Hmm, subregisters.  The simulated state is stored in memory in the
50    host's byte ordering, so we can't say here what the offsets of %ax,
51    %al, %ah etc are since that depends on the host's byte ordering,
52    which we don't know. */
53 
54 /* FPU.  For now, just simulate 8 64-bit registers, their tags, and
55    the reg-stack top pointer, of which only the least significant
56    three bits are relevant.
57 
58    The model is:
59      F0 .. F7 are the 8 registers.  FTOP[2:0] contains the
60      index of the current 'stack top' -- pretty meaningless, but
61      still.  FTOP is a 32-bit value.  FTOP[31:3] can be anything
62      (not guaranteed to be zero).
63 
64      When a value is pushed onto the stack, ftop is first replaced by
65      (ftop-1) & 7, and then F[ftop] is assigned the value.
66 
67      When a value is popped off the stack, the value is read from
68      F[ftop], and then ftop is replaced by (ftop+1) & 7.
69 
70      In general, a reference to a register ST(i) actually references
71      F[ (ftop+i) & 7 ].
72 
73    FTAG0 .. FTAG0+7 are the tags.  Each is a byte, zero means empty,
74    non-zero means non-empty.
75 
76    The general rule appears to be that a read or modify of a register
77    gets a stack underflow fault if the register is empty.  A write of
78    a register (only a write, not a modify) gets a stack overflow fault
79    if the register is full.  Note that "over" vs "under" is pretty
80    meaningless since the FP stack pointer can move around arbitrarily,
81    so it's really just two different kinds of exceptions:
82    register-empty and register full.
83 
84    Naturally Intel (in its infinite wisdom) has seen fit to throw in
85    some ad-hoc inconsistencies to the fault-generation rules of the
86    above para, just to complicate everything.  Known inconsistencies:
87 
88    * fxam can read a register in any state without taking an underflow
89      fault.
90 
91    * fst from st(0) to st(i) does not take an overflow fault even if the
92      destination is already full.
93 
94    FPROUND[1:0] is the FPU's notional rounding mode, encoded as per
95    the IRRoundingMode type (see libvex_ir.h).  This just happens to be
96    the Intel encoding.  Note carefully, the rounding mode is only
97    observed on float-to-int conversions, and on float-to-float
98    rounding, but not for general float-to-float operations, which are
99    always rounded-to-nearest.
100 
101    Loads/stores of the FPU control word are faked accordingly -- on
102    loads, everything except the rounding mode is ignored, and on
103    stores, you get a vanilla control world (0x037F) with the rounding
104    mode patched in.  Hence the only values you can get are 0x037F,
105    0x077F, 0x0B7F or 0x0F7F.  Vex will emit an emulation warning if
106    you try and load a control word which either (1) unmasks FP
107    exceptions, or (2) changes the default (80-bit) precision.
108 
109    FC3210 contains the C3, C2, C1 and C0 bits in the same place they
110    are in the FPU's status word.  (bits 14, 10, 9, 8 respectively).
111    All other bits should be zero.  The relevant mask to select just
112    those bits is 0x4700.  To select C3, C2 and C0 only, the mask is
113    0x4500.
114 
115    SSEROUND[1:0] is the SSE unit's notional rounding mode, encoded as
116    per the IRRoundingMode type.  As with the FPU control word, the
117    rounding mode is the only part of %MXCSR that Vex observes.  On
118    storing %MXCSR, you will get a vanilla word (0x1F80) with the
119    rounding mode patched in.  Hence the only values you will get are
120    0x1F80, 0x3F80, 0x5F80 or 0x7F80.  Vex will emit an emulation
121    warning if you try and load a control word which either (1) unmasks
122    any exceptions, (2) sets FZ (flush-to-zero) to 1, or (3) sets DAZ
123    (denormals-are-zeroes) to 1.
124 
125    Segments: initial prefixes of local and global segment descriptor
126    tables are modelled.  guest_LDT is either zero (NULL) or points in
127    the host address space to an array of VEX_GUEST_X86_LDT_NENT
128    descriptors, which have the type VexGuestX86SegDescr, defined
129    below.  Similarly, guest_GDT is either zero or points in the host
130    address space to an array of VEX_GUEST_X86_GDT_NENT descriptors.
131    The only place where these are used are in the helper function
132    x86g_use_seg().  LibVEX's client is responsible for pointing
133    guest_LDT and guest_GDT at suitable tables.  The contents of these
134    tables are expected not to change during the execution of any given
135    superblock, but they may validly be changed by LibVEX's client in
136    between superblock executions.
137 
138    Since x86g_use_seg() only expects these tables to have
139    VEX_GUEST_X86_{LDT,GDT}_NENT entries, LibVEX's client should not
140    attempt to write entries beyond those limits.
141 */
142 typedef
143    struct {
144       UInt  guest_EAX;         /* 0 */
145       UInt  guest_ECX;
146       UInt  guest_EDX;
147       UInt  guest_EBX;
148       UInt  guest_ESP;
149       UInt  guest_EBP;
150       UInt  guest_ESI;
151       UInt  guest_EDI;         /* 28 */
152 
153       /* 4-word thunk used to calculate O S Z A C P flags. */
154       UInt  guest_CC_OP;       /* 32 */
155       UInt  guest_CC_DEP1;
156       UInt  guest_CC_DEP2;
157       UInt  guest_CC_NDEP;     /* 44 */
158       /* The D flag is stored here, encoded as either -1 or +1 */
159       UInt  guest_DFLAG;       /* 48 */
160       /* Bit 21 (ID) of eflags stored here, as either 0 or 1. */
161       UInt  guest_IDFLAG;      /* 52 */
162       /* Bit 18 (AC) of eflags stored here, as either 0 or 1. */
163       UInt  guest_ACFLAG;      /* 56 */
164 
165       /* EIP */
166       UInt  guest_EIP;         /* 60 */
167 
168       /* FPU */
169       ULong guest_FPREG[8];    /* 64 */
170       UChar guest_FPTAG[8];   /* 128 */
171       UInt  guest_FPROUND;    /* 136 */
172       UInt  guest_FC3210;     /* 140 */
173       UInt  guest_FTOP;       /* 144 */
174 
175       /* SSE */
176       UInt  guest_SSEROUND;   /* 148 */
177       U128  guest_XMM0;       /* 152 */
178       U128  guest_XMM1;
179       U128  guest_XMM2;
180       U128  guest_XMM3;
181       U128  guest_XMM4;
182       U128  guest_XMM5;
183       U128  guest_XMM6;
184       U128  guest_XMM7;
185 
186       /* Segment registers. */
187       UShort guest_CS;
188       UShort guest_DS;
189       UShort guest_ES;
190       UShort guest_FS;
191       UShort guest_GS;
192       UShort guest_SS;
193       /* LDT/GDT stuff. */
194       HWord  guest_LDT; /* host addr, a VexGuestX86SegDescr* */
195       HWord  guest_GDT; /* host addr, a VexGuestX86SegDescr* */
196 
197       /* Emulation warnings */
198       UInt   guest_EMWARN;
199 
200       /* For clflush: record start and length of area to invalidate */
201       UInt guest_TISTART;
202       UInt guest_TILEN;
203 
204       /* Used to record the unredirected guest address at the start of
205          a translation whose start has been redirected.  By reading
206          this pseudo-register shortly afterwards, the translation can
207          find out what the corresponding no-redirection address was.
208          Note, this is only set for wrap-style redirects, not for
209          replace-style ones. */
210       UInt guest_NRADDR;
211 
212       /* Used for Darwin syscall dispatching. */
213       UInt guest_SC_CLASS;
214 
215       /* Needed for Darwin (but mandated for all guest architectures):
216          EIP at the last syscall insn (int 0x80/81/82, sysenter,
217          syscall).  Used when backing up to restart a syscall that has
218          been interrupted by a signal. */
219       UInt guest_IP_AT_SYSCALL;
220 
221       /* Padding to make it have an 16-aligned size */
222       UInt padding1;
223       UInt padding2;
224       UInt padding3;
225    }
226    VexGuestX86State;
227 
228 #define VEX_GUEST_X86_LDT_NENT /*64*/ 8192 /* use complete LDT */
229 #define VEX_GUEST_X86_GDT_NENT /*16*/ 8192 /* use complete GDT */
230 
231 
232 /*---------------------------------------------------------------*/
233 /*--- Types for x86 guest stuff.                              ---*/
234 /*---------------------------------------------------------------*/
235 
236 /* VISIBLE TO LIBRARY CLIENT */
237 
238 /* This is the hardware-format for a segment descriptor, ie what the
239    x86 actually deals with.  It is 8 bytes long.  It's ugly. */
240 
241 typedef struct {
242     union {
243        struct {
244           UShort  LimitLow;
245           UShort  BaseLow;
246           UInt    BaseMid         : 8;
247           UInt    Type            : 5;
248           UInt    Dpl             : 2;
249           UInt    Pres            : 1;
250           UInt    LimitHi         : 4;
251           UInt    Sys             : 1;
252           UInt    Reserved_0      : 1;
253           UInt    Default_Big     : 1;
254           UInt    Granularity     : 1;
255           UInt    BaseHi          : 8;
256        } Bits;
257        struct {
258           UInt word1;
259           UInt word2;
260        } Words;
261     }
262     LdtEnt;
263 } VexGuestX86SegDescr;
264 
265 
266 /*---------------------------------------------------------------*/
267 /*--- Utility functions for x86 guest stuff.                  ---*/
268 /*---------------------------------------------------------------*/
269 
270 /* ALL THE FOLLOWING ARE VISIBLE TO LIBRARY CLIENT */
271 
272 /* Initialise all guest x86 state.  The FPU is put in default mode. */
273 extern
274 void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state );
275 
276 
277 /* Extract from the supplied VexGuestX86State structure the
278    corresponding native %eflags value. */
279 extern
280 UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state );
281 
282 /* Set the carry flag in the given state to 'new_carry_flag', which
283    should be zero or one. */
284 extern
285 void
286 LibVEX_GuestX86_put_eflag_c ( UInt new_carry_flag,
287                               /*MOD*/VexGuestX86State* vex_state );
288 
289 #endif /* ndef __LIBVEX_PUB_GUEST_X86_H */
290 
291 /*---------------------------------------------------------------*/
292 /*---                                      libvex_guest_x86.h ---*/
293 /*---------------------------------------------------------------*/
294