sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 3 | /*--- begin libvex_guest_x86.h ---*/ |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 4 | /*---------------------------------------------------------------*/ |
| 5 | |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 6 | /* |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 9 | |
sewardj | 25e5473 | 2012-08-05 15:36:51 +0000 | [diff] [blame^] | 10 | Copyright (C) 2004-2012 OpenWorks LLP |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 11 | info@open-works.net |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 12 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 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. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 17 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 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 |
sewardj | 7bd6ffe | 2005-08-03 16:07:36 +0000 | [diff] [blame] | 26 | 02110-1301, USA. |
| 27 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 28 | The GNU General Public License is contained in the file COPYING. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 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. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 34 | */ |
| 35 | |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 36 | #ifndef __LIBVEX_PUB_GUEST_X86_H |
| 37 | #define __LIBVEX_PUB_GUEST_X86_H |
| 38 | |
| 39 | #include "libvex_basictypes.h" |
sewardj | 893aada | 2004-11-29 19:57:54 +0000 | [diff] [blame] | 40 | #include "libvex_emwarn.h" |
| 41 | |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 42 | |
| 43 | /*---------------------------------------------------------------*/ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 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 | |
sewardj | d01a963 | 2004-11-30 13:18:37 +0000 | [diff] [blame] | 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 |
sewardj | 7df596b | 2004-12-06 14:29:12 +0000 | [diff] [blame] | 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. |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 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 |
sewardj | 7df596b | 2004-12-06 14:29:12 +0000 | [diff] [blame] | 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 |
sewardj | 3bd6f3e | 2004-12-13 10:48:19 +0000 | [diff] [blame] | 123 | (denormals-are-zeroes) to 1. |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 124 | |
sewardj | 3bd6f3e | 2004-12-13 10:48:19 +0000 | [diff] [blame] | 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 | */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 142 | typedef |
| 143 | struct { |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 144 | /* Event check fail addr and counter. */ |
| 145 | UInt host_EvC_FAILADDR; /* 0 */ |
| 146 | UInt host_EvC_COUNTER; /* 4 */ |
| 147 | UInt guest_EAX; /* 8 */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 148 | UInt guest_ECX; |
| 149 | UInt guest_EDX; |
| 150 | UInt guest_EBX; |
| 151 | UInt guest_ESP; |
| 152 | UInt guest_EBP; |
| 153 | UInt guest_ESI; |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 154 | UInt guest_EDI; /* 36 */ |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 155 | |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 156 | /* 4-word thunk used to calculate O S Z A C P flags. */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 157 | UInt guest_CC_OP; /* 40 */ |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 158 | UInt guest_CC_DEP1; |
| 159 | UInt guest_CC_DEP2; |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 160 | UInt guest_CC_NDEP; /* 52 */ |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 161 | /* The D flag is stored here, encoded as either -1 or +1 */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 162 | UInt guest_DFLAG; /* 56 */ |
sewardj | 006a6a2 | 2004-10-26 00:50:52 +0000 | [diff] [blame] | 163 | /* Bit 21 (ID) of eflags stored here, as either 0 or 1. */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 164 | UInt guest_IDFLAG; /* 60 */ |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 165 | /* Bit 18 (AC) of eflags stored here, as either 0 or 1. */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 166 | UInt guest_ACFLAG; /* 64 */ |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 167 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 168 | /* EIP */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 169 | UInt guest_EIP; /* 68 */ |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 170 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 171 | /* FPU */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 172 | ULong guest_FPREG[8]; /* 72 */ |
| 173 | UChar guest_FPTAG[8]; /* 136 */ |
| 174 | UInt guest_FPROUND; /* 144 */ |
| 175 | UInt guest_FC3210; /* 148 */ |
| 176 | UInt guest_FTOP; /* 152 */ |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 177 | |
sewardj | c9a4366 | 2004-11-30 18:51:59 +0000 | [diff] [blame] | 178 | /* SSE */ |
sewardj | c6f970f | 2012-04-02 21:54:49 +0000 | [diff] [blame] | 179 | UInt guest_SSEROUND; /* 156 */ |
| 180 | U128 guest_XMM0; /* 160 */ |
sewardj | c9a4366 | 2004-11-30 18:51:59 +0000 | [diff] [blame] | 181 | U128 guest_XMM1; |
| 182 | U128 guest_XMM2; |
| 183 | U128 guest_XMM3; |
| 184 | U128 guest_XMM4; |
| 185 | U128 guest_XMM5; |
| 186 | U128 guest_XMM6; |
| 187 | U128 guest_XMM7; |
sewardj | 6d26984 | 2005-08-06 11:45:02 +0000 | [diff] [blame] | 188 | |
sewardj | 063f02f | 2004-10-20 12:36:12 +0000 | [diff] [blame] | 189 | /* Segment registers. */ |
| 190 | UShort guest_CS; |
| 191 | UShort guest_DS; |
| 192 | UShort guest_ES; |
| 193 | UShort guest_FS; |
| 194 | UShort guest_GS; |
| 195 | UShort guest_SS; |
sewardj | 3bd6f3e | 2004-12-13 10:48:19 +0000 | [diff] [blame] | 196 | /* LDT/GDT stuff. */ |
| 197 | HWord guest_LDT; /* host addr, a VexGuestX86SegDescr* */ |
| 198 | HWord guest_GDT; /* host addr, a VexGuestX86SegDescr* */ |
sewardj | 1f126c5 | 2005-03-16 13:57:58 +0000 | [diff] [blame] | 199 | |
sewardj | 893aada | 2004-11-29 19:57:54 +0000 | [diff] [blame] | 200 | /* Emulation warnings */ |
| 201 | UInt guest_EMWARN; |
sewardj | 1f126c5 | 2005-03-16 13:57:58 +0000 | [diff] [blame] | 202 | |
sewardj | ce02aa7 | 2006-01-12 12:27:58 +0000 | [diff] [blame] | 203 | /* For clflush: record start and length of area to invalidate */ |
sewardj | 1f126c5 | 2005-03-16 13:57:58 +0000 | [diff] [blame] | 204 | UInt guest_TISTART; |
| 205 | UInt guest_TILEN; |
| 206 | |
sewardj | ce02aa7 | 2006-01-12 12:27:58 +0000 | [diff] [blame] | 207 | /* Used to record the unredirected guest address at the start of |
| 208 | a translation whose start has been redirected. By reading |
| 209 | this pseudo-register shortly afterwards, the translation can |
| 210 | find out what the corresponding no-redirection address was. |
| 211 | Note, this is only set for wrap-style redirects, not for |
| 212 | replace-style ones. */ |
| 213 | UInt guest_NRADDR; |
| 214 | |
sewardj | d660d41 | 2008-12-03 21:29:59 +0000 | [diff] [blame] | 215 | /* Used for Darwin syscall dispatching. */ |
| 216 | UInt guest_SC_CLASS; |
| 217 | |
sewardj | e86310f | 2009-03-19 22:21:40 +0000 | [diff] [blame] | 218 | /* Needed for Darwin (but mandated for all guest architectures): |
| 219 | EIP at the last syscall insn (int 0x80/81/82, sysenter, |
| 220 | syscall). Used when backing up to restart a syscall that has |
| 221 | been interrupted by a signal. */ |
| 222 | UInt guest_IP_AT_SYSCALL; |
| 223 | |
sewardj | c4530ae | 2012-05-21 10:18:49 +0000 | [diff] [blame] | 224 | /* Padding to make it have an 32-aligned size */ |
| 225 | UInt padding[5]; |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 226 | } |
| 227 | VexGuestX86State; |
| 228 | |
sewardj | 3f46a01 | 2005-11-05 15:46:22 +0000 | [diff] [blame] | 229 | #define VEX_GUEST_X86_LDT_NENT /*64*/ 8192 /* use complete LDT */ |
| 230 | #define VEX_GUEST_X86_GDT_NENT /*16*/ 8192 /* use complete GDT */ |
sewardj | 3bd6f3e | 2004-12-13 10:48:19 +0000 | [diff] [blame] | 231 | |
| 232 | |
| 233 | /*---------------------------------------------------------------*/ |
| 234 | /*--- Types for x86 guest stuff. ---*/ |
| 235 | /*---------------------------------------------------------------*/ |
| 236 | |
| 237 | /* VISIBLE TO LIBRARY CLIENT */ |
| 238 | |
| 239 | /* This is the hardware-format for a segment descriptor, ie what the |
| 240 | x86 actually deals with. It is 8 bytes long. It's ugly. */ |
| 241 | |
| 242 | typedef struct { |
| 243 | union { |
| 244 | struct { |
| 245 | UShort LimitLow; |
| 246 | UShort BaseLow; |
| 247 | UInt BaseMid : 8; |
| 248 | UInt Type : 5; |
| 249 | UInt Dpl : 2; |
| 250 | UInt Pres : 1; |
| 251 | UInt LimitHi : 4; |
| 252 | UInt Sys : 1; |
| 253 | UInt Reserved_0 : 1; |
| 254 | UInt Default_Big : 1; |
| 255 | UInt Granularity : 1; |
| 256 | UInt BaseHi : 8; |
| 257 | } Bits; |
| 258 | struct { |
| 259 | UInt word1; |
| 260 | UInt word2; |
| 261 | } Words; |
| 262 | } |
| 263 | LdtEnt; |
| 264 | } VexGuestX86SegDescr; |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 265 | |
sewardj | 8d2291c | 2004-10-25 14:50:21 +0000 | [diff] [blame] | 266 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 267 | /*---------------------------------------------------------------*/ |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 268 | /*--- Utility functions for x86 guest stuff. ---*/ |
| 269 | /*---------------------------------------------------------------*/ |
| 270 | |
sewardj | 8d2291c | 2004-10-25 14:50:21 +0000 | [diff] [blame] | 271 | /* ALL THE FOLLOWING ARE VISIBLE TO LIBRARY CLIENT */ |
| 272 | |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 273 | /* Initialise all guest x86 state. The FPU is put in default mode. */ |
| 274 | extern |
| 275 | void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state ); |
| 276 | |
| 277 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 278 | /* Extract from the supplied VexGuestX86State structure the |
| 279 | corresponding native %eflags value. */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 280 | extern |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 281 | UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state ); |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 282 | |
sewardj | f32d5a5 | 2006-03-20 12:05:42 +0000 | [diff] [blame] | 283 | /* Set the carry flag in the given state to 'new_carry_flag', which |
| 284 | should be zero or one. */ |
| 285 | extern |
| 286 | void |
| 287 | LibVEX_GuestX86_put_eflag_c ( UInt new_carry_flag, |
| 288 | /*MOD*/VexGuestX86State* vex_state ); |
sewardj | 38a3f86 | 2005-01-13 15:06:51 +0000 | [diff] [blame] | 289 | |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 290 | #endif /* ndef __LIBVEX_PUB_GUEST_X86_H */ |
| 291 | |
| 292 | /*---------------------------------------------------------------*/ |
| 293 | /*--- libvex_guest_x86.h ---*/ |
| 294 | /*---------------------------------------------------------------*/ |