]> Git Repo - binutils.git/blob - gdb/gdbserver/win32-i386-low.c
[gdbserver] Fix watchpoint support on Windows
[binutils.git] / gdb / gdbserver / win32-i386-low.c
1 /* Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
2
3    This file is part of GDB.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 #include "server.h"
19 #include "win32-low.h"
20 #include "i386-low.h"
21
22 #ifndef CONTEXT_EXTENDED_REGISTERS
23 #define CONTEXT_EXTENDED_REGISTERS 0
24 #endif
25
26 #define FCS_REGNUM 27
27 #define FOP_REGNUM 31
28
29 #define FLAG_TRACE_BIT 0x100
30
31 #ifdef __x86_64__
32 /* Defined in auto-generated file reg-amd64.c.  */
33 void init_registers_amd64 (void);
34 #else
35 /* Defined in auto-generated file reg-i386.c.  */
36 void init_registers_i386 (void);
37 #endif
38
39 static struct i386_debug_reg_state debug_reg_state;
40
41 static int debug_registers_changed = 0;
42 static int debug_registers_used = 0;
43
44 /* Update the inferior's debug register REGNUM from STATE.  */
45
46 void
47 i386_dr_low_set_addr (const struct i386_debug_reg_state *state, int regnum)
48 {
49   if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
50     fatal ("Invalid debug register %d", regnum);
51
52   /* debug_reg_state.dr_mirror is already set.
53      Just notify i386_set_thread_context, i386_thread_added
54      that the registers need to be updated.  */
55   debug_registers_changed = 1;
56   debug_registers_used = 1;
57 }
58
59 CORE_ADDR
60 i386_dr_low_get_addr (int regnum)
61 {
62   gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
63
64   return debug_reg_state.dr_mirror[regnum];
65 }
66
67 /* Update the inferior's DR7 debug control register from STATE.  */
68
69 void
70 i386_dr_low_set_control (const struct i386_debug_reg_state *state)
71 {
72   /* debug_reg_state.dr_control_mirror is already set.
73      Just notify i386_set_thread_context, i386_thread_added
74      that the registers need to be updated.  */
75   debug_registers_changed = 1;
76   debug_registers_used = 1;
77 }
78
79 unsigned
80 i386_dr_low_get_control (void)
81 {
82   return debug_reg_state.dr_control_mirror;
83 }
84
85 /* Get the value of the DR6 debug status register from the inferior
86    and record it in STATE.  */
87
88 unsigned
89 i386_dr_low_get_status (void)
90 {
91   /* We don't need to do anything here, the last call to thread_rec for
92      current_event.dwThreadId id has already set it.  */
93   return debug_reg_state.dr_status_mirror;
94 }
95
96 /* Watchpoint support.  */
97
98 static int
99 i386_insert_point (char type, CORE_ADDR addr, int len)
100 {
101   switch (type)
102     {
103     case '2':
104     case '3':
105     case '4':
106       return i386_low_insert_watchpoint (&debug_reg_state,
107                                          type, addr, len);
108     default:
109       /* Unsupported.  */
110       return 1;
111     }
112 }
113
114 static int
115 i386_remove_point (char type, CORE_ADDR addr, int len)
116 {
117   switch (type)
118     {
119     case '2':
120     case '3':
121     case '4':
122       return i386_low_remove_watchpoint (&debug_reg_state,
123                                          type, addr, len);
124     default:
125       /* Unsupported.  */
126       return 1;
127     }
128 }
129
130 static int
131 i386_stopped_by_watchpoint (void)
132 {
133   return i386_low_stopped_by_watchpoint (&debug_reg_state);
134 }
135
136 static CORE_ADDR
137 i386_stopped_data_address (void)
138 {
139   CORE_ADDR addr;
140   if (i386_low_stopped_data_address (&debug_reg_state, &addr))
141     return addr;
142   return 0;
143 }
144
145 static void
146 i386_initial_stuff (void)
147 {
148   i386_low_init_dregs (&debug_reg_state);
149   debug_registers_changed = 0;
150   debug_registers_used = 0;
151 }
152
153 static void
154 i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
155 {
156   /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if
157      the system doesn't support extended registers.  */
158   static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS;
159
160  again:
161   th->context.ContextFlags = (CONTEXT_FULL
162                               | CONTEXT_FLOATING_POINT
163                               | CONTEXT_DEBUG_REGISTERS
164                               | extended_registers);
165
166   if (!GetThreadContext (th->h, &th->context))
167     {
168       DWORD e = GetLastError ();
169
170       if (extended_registers && e == ERROR_INVALID_PARAMETER)
171         {
172           extended_registers = 0;
173           goto again;
174         }
175
176       error ("GetThreadContext failure %ld\n", (long) e);
177     }
178
179   debug_registers_changed = 0;
180
181   if (th->tid == current_event->dwThreadId)
182     {
183       /* Copy dr values from the current thread.  */
184       struct i386_debug_reg_state *dr = &debug_reg_state;
185       dr->dr_mirror[0] = th->context.Dr0;
186       dr->dr_mirror[1] = th->context.Dr1;
187       dr->dr_mirror[2] = th->context.Dr2;
188       dr->dr_mirror[3] = th->context.Dr3;
189       dr->dr_status_mirror = th->context.Dr6;
190       dr->dr_control_mirror = th->context.Dr7;
191     }
192 }
193
194 static void
195 i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
196 {
197   if (debug_registers_changed)
198     {
199       struct i386_debug_reg_state *dr = &debug_reg_state;
200       th->context.Dr0 = dr->dr_mirror[0];
201       th->context.Dr1 = dr->dr_mirror[1];
202       th->context.Dr2 = dr->dr_mirror[2];
203       th->context.Dr3 = dr->dr_mirror[3];
204       /* th->context.Dr6 = dr->dr_status_mirror;
205          FIXME: should we set dr6 also ?? */
206       th->context.Dr7 = dr->dr_control_mirror;
207     }
208
209   SetThreadContext (th->h, &th->context);
210 }
211
212 static void
213 i386_thread_added (win32_thread_info *th)
214 {
215   /* Set the debug registers for the new thread if they are used.  */
216   if (debug_registers_used)
217     {
218       struct i386_debug_reg_state *dr = &debug_reg_state;
219       th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
220       GetThreadContext (th->h, &th->context);
221
222       th->context.Dr0 = dr->dr_mirror[0];
223       th->context.Dr1 = dr->dr_mirror[1];
224       th->context.Dr2 = dr->dr_mirror[2];
225       th->context.Dr3 = dr->dr_mirror[3];
226       /* th->context.Dr6 = dr->dr_status_mirror;
227          FIXME: should we set dr6 also ?? */
228       th->context.Dr7 = dr->dr_control_mirror;
229
230       SetThreadContext (th->h, &th->context);
231       th->context.ContextFlags = 0;
232     }
233 }
234
235 static void
236 i386_single_step (win32_thread_info *th)
237 {
238   th->context.EFlags |= FLAG_TRACE_BIT;
239 }
240
241 #ifndef __x86_64__
242
243 /* An array of offset mappings into a Win32 Context structure.
244    This is a one-to-one mapping which is indexed by gdb's register
245    numbers.  It retrieves an offset into the context structure where
246    the 4 byte register is located.
247    An offset value of -1 indicates that Win32 does not provide this
248    register in it's CONTEXT structure.  In this case regptr will return
249    a pointer into a dummy register.  */
250 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
251 static const int mappings[] = {
252   context_offset (Eax),
253   context_offset (Ecx),
254   context_offset (Edx),
255   context_offset (Ebx),
256   context_offset (Esp),
257   context_offset (Ebp),
258   context_offset (Esi),
259   context_offset (Edi),
260   context_offset (Eip),
261   context_offset (EFlags),
262   context_offset (SegCs),
263   context_offset (SegSs),
264   context_offset (SegDs),
265   context_offset (SegEs),
266   context_offset (SegFs),
267   context_offset (SegGs),
268   context_offset (FloatSave.RegisterArea[0 * 10]),
269   context_offset (FloatSave.RegisterArea[1 * 10]),
270   context_offset (FloatSave.RegisterArea[2 * 10]),
271   context_offset (FloatSave.RegisterArea[3 * 10]),
272   context_offset (FloatSave.RegisterArea[4 * 10]),
273   context_offset (FloatSave.RegisterArea[5 * 10]),
274   context_offset (FloatSave.RegisterArea[6 * 10]),
275   context_offset (FloatSave.RegisterArea[7 * 10]),
276   context_offset (FloatSave.ControlWord),
277   context_offset (FloatSave.StatusWord),
278   context_offset (FloatSave.TagWord),
279   context_offset (FloatSave.ErrorSelector),
280   context_offset (FloatSave.ErrorOffset),
281   context_offset (FloatSave.DataSelector),
282   context_offset (FloatSave.DataOffset),
283   context_offset (FloatSave.ErrorSelector),
284   /* XMM0-7 */
285   context_offset (ExtendedRegisters[10 * 16]),
286   context_offset (ExtendedRegisters[11 * 16]),
287   context_offset (ExtendedRegisters[12 * 16]),
288   context_offset (ExtendedRegisters[13 * 16]),
289   context_offset (ExtendedRegisters[14 * 16]),
290   context_offset (ExtendedRegisters[15 * 16]),
291   context_offset (ExtendedRegisters[16 * 16]),
292   context_offset (ExtendedRegisters[17 * 16]),
293   /* MXCSR */
294   context_offset (ExtendedRegisters[24])
295 };
296 #undef context_offset
297
298 #else /* __x86_64__ */
299
300 #define context_offset(x) (offsetof (CONTEXT, x))
301 static const int mappings[] =
302 {
303   context_offset (Rax),
304   context_offset (Rbx),
305   context_offset (Rcx),
306   context_offset (Rdx),
307   context_offset (Rsi),
308   context_offset (Rdi),
309   context_offset (Rbp),
310   context_offset (Rsp),
311   context_offset (R8),
312   context_offset (R9),
313   context_offset (R10),
314   context_offset (R11),
315   context_offset (R12),
316   context_offset (R13),
317   context_offset (R14),
318   context_offset (R15),
319   context_offset (Rip),
320   context_offset (EFlags),
321   context_offset (SegCs),
322   context_offset (SegSs),
323   context_offset (SegDs),
324   context_offset (SegEs),
325   context_offset (SegFs),
326   context_offset (SegGs),
327   context_offset (FloatSave.FloatRegisters[0]),
328   context_offset (FloatSave.FloatRegisters[1]),
329   context_offset (FloatSave.FloatRegisters[2]),
330   context_offset (FloatSave.FloatRegisters[3]),
331   context_offset (FloatSave.FloatRegisters[4]),
332   context_offset (FloatSave.FloatRegisters[5]),
333   context_offset (FloatSave.FloatRegisters[6]),
334   context_offset (FloatSave.FloatRegisters[7]),
335   context_offset (FloatSave.ControlWord),
336   context_offset (FloatSave.StatusWord),
337   context_offset (FloatSave.TagWord),
338   context_offset (FloatSave.ErrorSelector),
339   context_offset (FloatSave.ErrorOffset),
340   context_offset (FloatSave.DataSelector),
341   context_offset (FloatSave.DataOffset),
342   context_offset (FloatSave.ErrorSelector)
343   /* XMM0-7 */ ,
344   context_offset (Xmm0),
345   context_offset (Xmm1),
346   context_offset (Xmm2),
347   context_offset (Xmm3),
348   context_offset (Xmm4),
349   context_offset (Xmm5),
350   context_offset (Xmm6),
351   context_offset (Xmm7),
352   context_offset (Xmm8),
353   context_offset (Xmm9),
354   context_offset (Xmm10),
355   context_offset (Xmm11),
356   context_offset (Xmm12),
357   context_offset (Xmm13),
358   context_offset (Xmm14),
359   context_offset (Xmm15),
360   /* MXCSR */
361   context_offset (FloatSave.MxCsr)
362 };
363 #undef context_offset
364
365 #endif /* __x86_64__ */
366
367 /* Fetch register from gdbserver regcache data.  */
368 static void
369 i386_fetch_inferior_register (struct regcache *regcache,
370                               win32_thread_info *th, int r)
371 {
372   char *context_offset = (char *) &th->context + mappings[r];
373
374   long l;
375   if (r == FCS_REGNUM)
376     {
377       l = *((long *) context_offset) & 0xffff;
378       supply_register (regcache, r, (char *) &l);
379     }
380   else if (r == FOP_REGNUM)
381     {
382       l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
383       supply_register (regcache, r, (char *) &l);
384     }
385   else
386     supply_register (regcache, r, context_offset);
387 }
388
389 /* Store a new register value into the thread context of TH.  */
390 static void
391 i386_store_inferior_register (struct regcache *regcache,
392                               win32_thread_info *th, int r)
393 {
394   char *context_offset = (char *) &th->context + mappings[r];
395   collect_register (regcache, r, context_offset);
396 }
397
398 static const unsigned char i386_win32_breakpoint = 0xcc;
399 #define i386_win32_breakpoint_len 1
400
401 static void
402 init_windows_x86 (void)
403 {
404 #ifdef __x86_64__
405   init_registers_amd64 ();
406 #else
407   init_registers_i386 ();
408 #endif
409 }
410
411 struct win32_target_ops the_low_target = {
412   init_windows_x86,
413   sizeof (mappings) / sizeof (mappings[0]),
414   i386_initial_stuff,
415   i386_get_thread_context,
416   i386_set_thread_context,
417   i386_thread_added,
418   i386_fetch_inferior_register,
419   i386_store_inferior_register,
420   i386_single_step,
421   &i386_win32_breakpoint,
422   i386_win32_breakpoint_len,
423   i386_insert_point,
424   i386_remove_point,
425   i386_stopped_by_watchpoint,
426   i386_stopped_data_address
427 };
This page took 0.052007 seconds and 4 git commands to generate.