sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
| 3 | /*--- ---*/ |
| 4 | /*--- This file (libvex_guest_x86.h) is ---*/ |
| 5 | /*--- Copyright (c) 2004 OpenWorks LLP. All rights reserved. ---*/ |
| 6 | /*--- ---*/ |
| 7 | /*---------------------------------------------------------------*/ |
| 8 | |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 9 | /* |
| 10 | This file is part of LibVEX, a library for dynamic binary |
| 11 | instrumentation and translation. |
| 12 | |
| 13 | Copyright (C) 2004 OpenWorks, LLP. |
| 14 | |
| 15 | This program is free software; you can redistribute it and/or modify |
| 16 | it under the terms of the GNU General Public License as published by |
| 17 | the Free Software Foundation; Version 2 dated June 1991 of the |
| 18 | license. |
| 19 | |
| 20 | This program is distributed in the hope that it will be useful, |
| 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability |
| 23 | for damages. See the GNU General Public License for more details. |
| 24 | |
| 25 | Neither the names of the U.S. Department of Energy nor the |
| 26 | University of California nor the names of its contributors may be |
| 27 | used to endorse or promote products derived from this software |
| 28 | without prior written permission. |
| 29 | |
| 30 | You should have received a copy of the GNU General Public License |
| 31 | along with this program; if not, write to the Free Software |
| 32 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| 33 | USA. |
| 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 |
| 123 | (denormals-are-zeroes) to 1. */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 124 | |
| 125 | typedef |
| 126 | struct { |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 127 | UInt guest_EAX; /* 0 */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 128 | UInt guest_ECX; |
| 129 | UInt guest_EDX; |
| 130 | UInt guest_EBX; |
| 131 | UInt guest_ESP; |
| 132 | UInt guest_EBP; |
| 133 | UInt guest_ESI; |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 134 | UInt guest_EDI; /* 28 */ |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 135 | /* 4-word thunk used to calculate O S Z A C P flags. */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 136 | UInt guest_CC_OP; /* 32 */ |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 137 | UInt guest_CC_DEP1; |
| 138 | UInt guest_CC_DEP2; |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 139 | UInt guest_CC_NDEP; /* 44 */ |
sewardj | 2a2ba8b | 2004-11-08 13:14:06 +0000 | [diff] [blame] | 140 | /* The D flag is stored here, encoded as either -1 or +1 */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 141 | UInt guest_DFLAG; /* 48 */ |
sewardj | 006a6a2 | 2004-10-26 00:50:52 +0000 | [diff] [blame] | 142 | /* Bit 21 (ID) of eflags stored here, as either 0 or 1. */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 143 | UInt guest_IDFLAG; /* 52 */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 144 | /* EIP */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 145 | UInt guest_EIP; /* 56 */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 146 | /* FPU */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 147 | UInt guest_FTOP; /* 60 */ |
| 148 | ULong guest_FPREG[8]; /* 64 */ |
| 149 | UChar guest_FPTAG[8]; /* 128 */ |
| 150 | UInt guest_FPROUND; /* 136 */ |
| 151 | UInt guest_FC3210; /* 140 */ |
sewardj | c9a4366 | 2004-11-30 18:51:59 +0000 | [diff] [blame] | 152 | /* SSE */ |
sewardj | 70f676d | 2004-12-10 14:59:57 +0000 | [diff] [blame^] | 153 | UInt guest_SSEROUND; /* 144 */ |
| 154 | U128 guest_XMM0; /* 148 */ |
sewardj | c9a4366 | 2004-11-30 18:51:59 +0000 | [diff] [blame] | 155 | U128 guest_XMM1; |
| 156 | U128 guest_XMM2; |
| 157 | U128 guest_XMM3; |
| 158 | U128 guest_XMM4; |
| 159 | U128 guest_XMM5; |
| 160 | U128 guest_XMM6; |
| 161 | U128 guest_XMM7; |
sewardj | 063f02f | 2004-10-20 12:36:12 +0000 | [diff] [blame] | 162 | /* Segment registers. */ |
| 163 | UShort guest_CS; |
| 164 | UShort guest_DS; |
| 165 | UShort guest_ES; |
| 166 | UShort guest_FS; |
| 167 | UShort guest_GS; |
| 168 | UShort guest_SS; |
sewardj | 893aada | 2004-11-29 19:57:54 +0000 | [diff] [blame] | 169 | /* Emulation warnings */ |
| 170 | UInt guest_EMWARN; |
sewardj | 81ec418 | 2004-10-25 23:15:52 +0000 | [diff] [blame] | 171 | /* Padding to make it have an 8-aligned size */ |
sewardj | c9a4366 | 2004-11-30 18:51:59 +0000 | [diff] [blame] | 172 | UInt padding; |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 173 | } |
| 174 | VexGuestX86State; |
| 175 | |
| 176 | |
sewardj | 8d2291c | 2004-10-25 14:50:21 +0000 | [diff] [blame] | 177 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 178 | /*---------------------------------------------------------------*/ |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 179 | /*--- Utility functions for x86 guest stuff. ---*/ |
| 180 | /*---------------------------------------------------------------*/ |
| 181 | |
sewardj | 8d2291c | 2004-10-25 14:50:21 +0000 | [diff] [blame] | 182 | |
sewardj | 8d2291c | 2004-10-25 14:50:21 +0000 | [diff] [blame] | 183 | /* ALL THE FOLLOWING ARE VISIBLE TO LIBRARY CLIENT */ |
| 184 | |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 185 | |
| 186 | /* Initialise all guest x86 state. The FPU is put in default mode. */ |
| 187 | extern |
| 188 | void LibVEX_GuestX86_initialise ( /*OUT*/VexGuestX86State* vex_state ); |
| 189 | |
| 190 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 191 | /* Convert a saved x87 FPU image (as created by fsave) and write it |
| 192 | into the supplied VexGuestX86State structure. The non-FP parts of |
sewardj | 893aada | 2004-11-29 19:57:54 +0000 | [diff] [blame] | 193 | said structure are left unchanged. May return an emulation warning |
| 194 | value. |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 195 | */ |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 196 | extern |
sewardj | 893aada | 2004-11-29 19:57:54 +0000 | [diff] [blame] | 197 | VexEmWarn |
| 198 | LibVEX_GuestX86_put_x87 ( /*IN*/UChar* x87_state, |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 199 | /*OUT*/VexGuestX86State* vex_state ); |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 200 | |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 201 | /* Extract from the supplied VexGuestX86State structure, an x87 FPU |
| 202 | image. */ |
| 203 | extern |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 204 | void LibVEX_GuestX86_get_x87 ( /*IN*/VexGuestX86State* vex_state, |
| 205 | /*OUT*/UChar* x87_state ); |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 206 | |
| 207 | |
| 208 | /* Given a 32-bit word containing native x86 %eflags values, set the |
| 209 | eflag-related fields in the supplied VexGuestX86State accordingly. |
| 210 | All other fields are left unchanged. */ |
| 211 | |
| 212 | extern |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 213 | void LibVEX_GuestX86_put_eflags ( UInt eflags_native, |
| 214 | /*OUT*/VexGuestX86State* vex_state ); |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 215 | |
| 216 | /* Extract from the supplied VexGuestX86State structure the |
| 217 | corresponding native %eflags value. */ |
| 218 | |
| 219 | extern |
sewardj | 76bdc80 | 2004-10-25 15:33:26 +0000 | [diff] [blame] | 220 | UInt LibVEX_GuestX86_get_eflags ( /*IN*/VexGuestX86State* vex_state ); |
sewardj | f6dc3ce | 2004-10-19 01:03:46 +0000 | [diff] [blame] | 221 | |
sewardj | 0c2cb62 | 2004-09-06 23:21:21 +0000 | [diff] [blame] | 222 | |
| 223 | #endif /* ndef __LIBVEX_PUB_GUEST_X86_H */ |
| 224 | |
| 225 | /*---------------------------------------------------------------*/ |
| 226 | /*--- libvex_guest_x86.h ---*/ |
| 227 | /*---------------------------------------------------------------*/ |