1 /* Low level interface to valgrind, for the remote server for GDB integrated
4 Free Software Foundation, Inc.
6 This file is part of VALGRIND.
7 It has been inspired from a file from gdbserver in gdb 6.6.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 Boston, MA 02110-1301, USA. */
29 #include "pub_core_machine.h"
30 #include "pub_core_threadstate.h"
31 #include "pub_core_transtab.h"
32 #include "pub_core_gdbserver.h"
34 #include "valgrind_low.h"
36 #include "libvex_guest_x86.h"
37 /* GDBTD: ??? have a cleaner way to get the f80 <> f64 conversion functions */
38 /* below include needed for conversion f80 <> f64 */
39 #include "../../VEX/priv/guest_generic_x87.h"
42 /* below loosely inspired from file generated with gdb regdat.sh */
44 static struct reg regs
[] = {
54 { "eflags", 288, 32 },
69 { "fctrl", 1152, 32 },
70 { "fstat", 1184, 32 },
72 { "fiseg", 1248, 32 },
73 { "fioff", 1280, 32 },
74 { "foseg", 1312, 32 },
75 { "fooff", 1344, 32 },
77 { "xmm0", 1408, 128 },
78 { "xmm1", 1536, 128 },
79 { "xmm2", 1664, 128 },
80 { "xmm3", 1792, 128 },
81 { "xmm4", 1920, 128 },
82 { "xmm5", 2048, 128 },
83 { "xmm6", 2176, 128 },
84 { "xmm7", 2304, 128 },
85 { "mxcsr", 2432, 32 },
86 #if defined(VGO_linux)
87 { "orig_eax", 2464, 32 }
90 static const char *expedite_regs
[] = { "ebp", "esp", "eip", 0 };
91 #define num_regs (sizeof (regs) / sizeof (regs[0]))
94 CORE_ADDR
get_pc (void)
98 collect_register_by_name ("eip", &pc
);
100 dlog(1, "stop pc is %p\n", (void *) pc
);
105 void set_pc (CORE_ADDR newpc
)
108 supply_register_by_name ("eip", &newpc
, &mod
);
110 dlog(1, "set pc to %p\n", C2v (newpc
));
112 dlog(1, "set pc not changed %p\n", C2v (newpc
));
115 /* store registers in the guest state (gdbserver_to_valgrind)
116 or fetch register from the guest state (valgrind_to_gdbserver). */
118 void transfer_register (ThreadId tid
, int abs_regno
, void * buf
,
119 transfer_direction dir
, int size
, Bool
*mod
)
121 ThreadState
* tst
= VG_(get_ThreadState
)(tid
);
122 int set
= abs_regno
/ num_regs
;
123 int regno
= abs_regno
% num_regs
;
126 VexGuestX86State
* x86
= (VexGuestX86State
*) get_arch (set
, tst
);
129 // numbers here have to match the order of regs above
130 // Attention: gdb order does not match valgrind order.
131 case 0: VG_(transfer
) (&x86
->guest_EAX
, buf
, dir
, size
, mod
); break;
132 case 1: VG_(transfer
) (&x86
->guest_ECX
, buf
, dir
, size
, mod
); break;
133 case 2: VG_(transfer
) (&x86
->guest_EDX
, buf
, dir
, size
, mod
); break;
134 case 3: VG_(transfer
) (&x86
->guest_EBX
, buf
, dir
, size
, mod
); break;
135 case 4: VG_(transfer
) (&x86
->guest_ESP
, buf
, dir
, size
, mod
); break;
136 case 5: VG_(transfer
) (&x86
->guest_EBP
, buf
, dir
, size
, mod
); break;
137 case 6: VG_(transfer
) (&x86
->guest_ESI
, buf
, dir
, size
, mod
); break;
138 case 7: VG_(transfer
) (&x86
->guest_EDI
, buf
, dir
, size
, mod
); break;
139 case 8: VG_(transfer
) (&x86
->guest_EIP
, buf
, dir
, size
, mod
); break;
141 if (dir
== valgrind_to_gdbserver
) {
143 /* we can only retrieve the real flags (set 0)
144 retrieving shadow flags is not ok */
146 eflags
= LibVEX_GuestX86_get_eflags (x86
);
149 VG_(transfer
) (&eflags
, buf
, dir
, size
, mod
); break;
151 *mod
= False
; //GDBTD? how do we store eflags in libvex_guest_x86.h ???
154 case 10: VG_(transfer
) (&x86
->guest_CS
, buf
, dir
, size
, mod
); break;
155 case 11: VG_(transfer
) (&x86
->guest_SS
, buf
, dir
, size
, mod
); break;
156 case 12: VG_(transfer
) (&x86
->guest_DS
, buf
, dir
, size
, mod
); break;
157 case 13: VG_(transfer
) (&x86
->guest_ES
, buf
, dir
, size
, mod
); break;
158 case 14: VG_(transfer
) (&x86
->guest_FS
, buf
, dir
, size
, mod
); break;
159 case 15: VG_(transfer
) (&x86
->guest_GS
, buf
, dir
, size
, mod
); break;
163 case 19: /* register 16 to 23 are float registers 80 bits but 64 bits in valgrind */
168 if (dir
== valgrind_to_gdbserver
) {
170 convert_f64le_to_f80le ((UChar
*)&x86
->guest_FPREG
[regno
-16],
172 VG_(transfer
) (&fpreg80
, buf
, dir
, sizeof(fpreg80
), mod
);
175 convert_f80le_to_f64le (buf
, (UChar
*)&fpreg64
);
176 VG_(transfer
) (&x86
->guest_FPREG
[regno
-16], &fpreg64
,
177 dir
, sizeof(fpreg64
), mod
);
182 if (dir
== valgrind_to_gdbserver
) {
183 // vex only models the rounding bits (see libvex_guest_x86.h)
184 UWord value
= 0x037f;
185 value
|= x86
->guest_FPROUND
<< 10;
186 VG_(transfer
)(&value
, buf
, dir
, size
, mod
);
188 *mod
= False
; // GDBTD???? VEX { "fctrl", 1152, 32 },
192 if (dir
== valgrind_to_gdbserver
) {
193 UWord value
= x86
->guest_FC3210
;
194 value
|= (x86
->guest_FTOP
& 7) << 11;
195 VG_(transfer
)(&value
, buf
, dir
, size
, mod
);
197 *mod
= False
; // GDBTD???? VEX { "fstat", 1184, 32 },
201 if (dir
== valgrind_to_gdbserver
) {
202 // vex doesn't model these precisely
204 ((x86
->guest_FPTAG
[0] ? 0 : 3) << 0) |
205 ((x86
->guest_FPTAG
[1] ? 0 : 3) << 2) |
206 ((x86
->guest_FPTAG
[2] ? 0 : 3) << 4) |
207 ((x86
->guest_FPTAG
[3] ? 0 : 3) << 6) |
208 ((x86
->guest_FPTAG
[4] ? 0 : 3) << 8) |
209 ((x86
->guest_FPTAG
[5] ? 0 : 3) << 10) |
210 ((x86
->guest_FPTAG
[6] ? 0 : 3) << 12) |
211 ((x86
->guest_FPTAG
[7] ? 0 : 3) << 14);
212 VG_(transfer
)(&value
, buf
, dir
, size
, mod
);
214 *mod
= False
; // GDBTD???? VEX { "ftag", 1216, 32 },
217 case 27: *mod
= False
; break; // GDBTD???? VEX { "fiseg", 1248, 32 },
218 case 28: *mod
= False
; break; // GDBTD???? VEX { "fioff", 1280, 32 },
219 case 29: *mod
= False
; break; // GDBTD???? VEX { "foseg", 1312, 32 },
220 case 30: *mod
= False
; break; // GDBTD???? VEX { "fooff", 1344, 32 },
221 case 31: *mod
= False
; break; // GDBTD???? VEX { "fop", 1376, 32 },
222 case 32: VG_(transfer
) (&x86
->guest_XMM0
, buf
, dir
, size
, mod
); break;
223 case 33: VG_(transfer
) (&x86
->guest_XMM1
, buf
, dir
, size
, mod
); break;
224 case 34: VG_(transfer
) (&x86
->guest_XMM2
, buf
, dir
, size
, mod
); break;
225 case 35: VG_(transfer
) (&x86
->guest_XMM3
, buf
, dir
, size
, mod
); break;
226 case 36: VG_(transfer
) (&x86
->guest_XMM4
, buf
, dir
, size
, mod
); break;
227 case 37: VG_(transfer
) (&x86
->guest_XMM5
, buf
, dir
, size
, mod
); break;
228 case 38: VG_(transfer
) (&x86
->guest_XMM6
, buf
, dir
, size
, mod
); break;
229 case 39: VG_(transfer
) (&x86
->guest_XMM7
, buf
, dir
, size
, mod
); break;
231 if (dir
== valgrind_to_gdbserver
) {
232 // vex only models the rounding bits (see libvex_guest_x86.h)
233 UWord value
= 0x1f80;
234 value
|= x86
->guest_SSEROUND
<< 13;
235 VG_(transfer
)(&value
, buf
, dir
, size
, mod
);
237 *mod
= False
; // GDBTD???? VEX { "mxcsr", 2432, 32 },
240 case 41: *mod
= False
; break; // GDBTD???? VEX { "orig_eax", 2464, 32 },
241 default: vg_assert(0);
246 const char* target_xml (Bool shadow_mode
)
249 #if defined(VGO_linux)
250 return "i386-linux-valgrind.xml";
252 return "i386-coresse-valgrind.xml";
259 static CORE_ADDR
** target_get_dtv (ThreadState
*tst
)
261 VexGuestX86State
* x86
= (VexGuestX86State
*)&tst
->arch
.vex
;
262 // FIXME: should make the below formally visible from VEX.
263 extern ULong
x86g_use_seg_selector ( HWord ldt
, HWord gdt
,
264 UInt seg_selector
, UInt virtual_addr
);
266 ULong dtv_loc_g
= x86g_use_seg_selector (x86
->guest_LDT
,
270 if (dtv_loc_g
== 1ULL << 32) {
271 dlog(0, "Error getting x86 dtv\n");
274 CORE_ADDR dtv_loc
= dtv_loc_g
;
275 return (CORE_ADDR
**)dtv_loc
;
279 static struct valgrind_target_ops low_target
= {
291 void x86_init_architecture (struct valgrind_target_ops
*target
)
293 *target
= low_target
;
294 set_register_cache (regs
, num_regs
);
295 gdbserver_expedite_regs
= expedite_regs
;