Vectorize gdbserver x86 debug register accessors
[external/binutils.git] / gdb / gdbserver / win32-i386-low.c
1 /* Copyright (C) 2007-2014 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 extern const struct target_desc *tdesc_amd64;
35 #else
36 /* Defined in auto-generated file reg-i386.c.  */
37 void init_registers_i386 (void);
38 extern const struct target_desc *tdesc_i386;
39 #endif
40
41 static struct i386_debug_reg_state debug_reg_state;
42
43 static int debug_registers_changed = 0;
44 static int debug_registers_used = 0;
45
46 /* Update the inferior's debug register REGNUM from STATE.  */
47
48 static void
49 i386_dr_low_set_addr (int regnum, CORE_ADDR addr)
50 {
51   if (! (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR))
52     fatal ("Invalid debug register %d", regnum);
53
54   /* debug_reg_state.dr_mirror is already set.
55      Just notify i386_set_thread_context, i386_thread_added
56      that the registers need to be updated.  */
57   debug_registers_changed = 1;
58   debug_registers_used = 1;
59 }
60
61 static CORE_ADDR
62 i386_dr_low_get_addr (int regnum)
63 {
64   gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR);
65
66   return debug_reg_state.dr_mirror[regnum];
67 }
68
69 /* Update the inferior's DR7 debug control register from STATE.  */
70
71 static void
72 i386_dr_low_set_control (unsigned long control)
73 {
74   /* debug_reg_state.dr_control_mirror is already set.
75      Just notify i386_set_thread_context, i386_thread_added
76      that the registers need to be updated.  */
77   debug_registers_changed = 1;
78   debug_registers_used = 1;
79 }
80
81 static unsigned long
82 i386_dr_low_get_control (void)
83 {
84   return debug_reg_state.dr_control_mirror;
85 }
86
87 /* Get the value of the DR6 debug status register from the inferior
88    and record it in STATE.  */
89
90 static unsigned long
91 i386_dr_low_get_status (void)
92 {
93   /* We don't need to do anything here, the last call to thread_rec for
94      current_event.dwThreadId id has already set it.  */
95   return debug_reg_state.dr_status_mirror;
96 }
97
98 /* Low-level function vector.  */
99 struct i386_dr_low_type i386_dr_low =
100   {
101     i386_dr_low_set_control,
102     i386_dr_low_set_addr,
103     i386_dr_low_get_addr,
104     i386_dr_low_get_status,
105     i386_dr_low_get_control,
106     sizeof (void *),
107   };
108
109 /* Breakpoint/watchpoint support.  */
110
111 static int
112 i386_supports_z_point_type (char z_type)
113 {
114   switch (z_type)
115     {
116     case Z_PACKET_WRITE_WP:
117     case Z_PACKET_ACCESS_WP:
118       return 1;
119     default:
120       return 0;
121     }
122 }
123
124 static int
125 i386_insert_point (enum raw_bkpt_type type, CORE_ADDR addr,
126                    int size, struct raw_breakpoint *bp)
127 {
128   switch (type)
129     {
130     case raw_bkpt_type_write_wp:
131     case raw_bkpt_type_access_wp:
132       {
133         enum target_hw_bp_type hw_type
134           = raw_bkpt_type_to_target_hw_bp_type (type);
135
136         return i386_dr_insert_watchpoint (&debug_reg_state,
137                                           hw_type, addr, size);
138       }
139     default:
140       /* Unsupported.  */
141       return 1;
142     }
143 }
144
145 static int
146 i386_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
147                    int size, struct raw_breakpoint *bp)
148 {
149   switch (type)
150     {
151     case raw_bkpt_type_write_wp:
152     case raw_bkpt_type_access_wp:
153       {
154         enum target_hw_bp_type hw_type
155           = raw_bkpt_type_to_target_hw_bp_type (type);
156
157         return i386_dr_remove_watchpoint (&debug_reg_state,
158                                           hw_type, addr, size);
159       }
160     default:
161       /* Unsupported.  */
162       return 1;
163     }
164 }
165
166 static int
167 i386_stopped_by_watchpoint (void)
168 {
169   return i386_dr_stopped_by_watchpoint (&debug_reg_state);
170 }
171
172 static CORE_ADDR
173 i386_stopped_data_address (void)
174 {
175   CORE_ADDR addr;
176   if (i386_dr_stopped_data_address (&debug_reg_state, &addr))
177     return addr;
178   return 0;
179 }
180
181 static void
182 i386_initial_stuff (void)
183 {
184   i386_low_init_dregs (&debug_reg_state);
185   debug_registers_changed = 0;
186   debug_registers_used = 0;
187 }
188
189 static void
190 i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
191 {
192   /* Requesting the CONTEXT_EXTENDED_REGISTERS register set fails if
193      the system doesn't support extended registers.  */
194   static DWORD extended_registers = CONTEXT_EXTENDED_REGISTERS;
195
196  again:
197   th->context.ContextFlags = (CONTEXT_FULL
198                               | CONTEXT_FLOATING_POINT
199                               | CONTEXT_DEBUG_REGISTERS
200                               | extended_registers);
201
202   if (!GetThreadContext (th->h, &th->context))
203     {
204       DWORD e = GetLastError ();
205
206       if (extended_registers && e == ERROR_INVALID_PARAMETER)
207         {
208           extended_registers = 0;
209           goto again;
210         }
211
212       error ("GetThreadContext failure %ld\n", (long) e);
213     }
214
215   debug_registers_changed = 0;
216
217   if (th->tid == current_event->dwThreadId)
218     {
219       /* Copy dr values from the current thread.  */
220       struct i386_debug_reg_state *dr = &debug_reg_state;
221       dr->dr_mirror[0] = th->context.Dr0;
222       dr->dr_mirror[1] = th->context.Dr1;
223       dr->dr_mirror[2] = th->context.Dr2;
224       dr->dr_mirror[3] = th->context.Dr3;
225       dr->dr_status_mirror = th->context.Dr6;
226       dr->dr_control_mirror = th->context.Dr7;
227     }
228 }
229
230 static void
231 i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
232 {
233   if (debug_registers_changed)
234     {
235       struct i386_debug_reg_state *dr = &debug_reg_state;
236       th->context.Dr0 = dr->dr_mirror[0];
237       th->context.Dr1 = dr->dr_mirror[1];
238       th->context.Dr2 = dr->dr_mirror[2];
239       th->context.Dr3 = dr->dr_mirror[3];
240       /* th->context.Dr6 = dr->dr_status_mirror;
241          FIXME: should we set dr6 also ?? */
242       th->context.Dr7 = dr->dr_control_mirror;
243     }
244
245   SetThreadContext (th->h, &th->context);
246 }
247
248 static void
249 i386_thread_added (win32_thread_info *th)
250 {
251   /* Set the debug registers for the new thread if they are used.  */
252   if (debug_registers_used)
253     {
254       struct i386_debug_reg_state *dr = &debug_reg_state;
255       th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
256       GetThreadContext (th->h, &th->context);
257
258       th->context.Dr0 = dr->dr_mirror[0];
259       th->context.Dr1 = dr->dr_mirror[1];
260       th->context.Dr2 = dr->dr_mirror[2];
261       th->context.Dr3 = dr->dr_mirror[3];
262       /* th->context.Dr6 = dr->dr_status_mirror;
263          FIXME: should we set dr6 also ?? */
264       th->context.Dr7 = dr->dr_control_mirror;
265
266       SetThreadContext (th->h, &th->context);
267       th->context.ContextFlags = 0;
268     }
269 }
270
271 static void
272 i386_single_step (win32_thread_info *th)
273 {
274   th->context.EFlags |= FLAG_TRACE_BIT;
275 }
276
277 #ifndef __x86_64__
278
279 /* An array of offset mappings into a Win32 Context structure.
280    This is a one-to-one mapping which is indexed by gdb's register
281    numbers.  It retrieves an offset into the context structure where
282    the 4 byte register is located.
283    An offset value of -1 indicates that Win32 does not provide this
284    register in it's CONTEXT structure.  In this case regptr will return
285    a pointer into a dummy register.  */
286 #define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
287 static const int mappings[] = {
288   context_offset (Eax),
289   context_offset (Ecx),
290   context_offset (Edx),
291   context_offset (Ebx),
292   context_offset (Esp),
293   context_offset (Ebp),
294   context_offset (Esi),
295   context_offset (Edi),
296   context_offset (Eip),
297   context_offset (EFlags),
298   context_offset (SegCs),
299   context_offset (SegSs),
300   context_offset (SegDs),
301   context_offset (SegEs),
302   context_offset (SegFs),
303   context_offset (SegGs),
304   context_offset (FloatSave.RegisterArea[0 * 10]),
305   context_offset (FloatSave.RegisterArea[1 * 10]),
306   context_offset (FloatSave.RegisterArea[2 * 10]),
307   context_offset (FloatSave.RegisterArea[3 * 10]),
308   context_offset (FloatSave.RegisterArea[4 * 10]),
309   context_offset (FloatSave.RegisterArea[5 * 10]),
310   context_offset (FloatSave.RegisterArea[6 * 10]),
311   context_offset (FloatSave.RegisterArea[7 * 10]),
312   context_offset (FloatSave.ControlWord),
313   context_offset (FloatSave.StatusWord),
314   context_offset (FloatSave.TagWord),
315   context_offset (FloatSave.ErrorSelector),
316   context_offset (FloatSave.ErrorOffset),
317   context_offset (FloatSave.DataSelector),
318   context_offset (FloatSave.DataOffset),
319   context_offset (FloatSave.ErrorSelector),
320   /* XMM0-7 */
321   context_offset (ExtendedRegisters[10 * 16]),
322   context_offset (ExtendedRegisters[11 * 16]),
323   context_offset (ExtendedRegisters[12 * 16]),
324   context_offset (ExtendedRegisters[13 * 16]),
325   context_offset (ExtendedRegisters[14 * 16]),
326   context_offset (ExtendedRegisters[15 * 16]),
327   context_offset (ExtendedRegisters[16 * 16]),
328   context_offset (ExtendedRegisters[17 * 16]),
329   /* MXCSR */
330   context_offset (ExtendedRegisters[24])
331 };
332 #undef context_offset
333
334 #else /* __x86_64__ */
335
336 #define context_offset(x) (offsetof (CONTEXT, x))
337 static const int mappings[] =
338 {
339   context_offset (Rax),
340   context_offset (Rbx),
341   context_offset (Rcx),
342   context_offset (Rdx),
343   context_offset (Rsi),
344   context_offset (Rdi),
345   context_offset (Rbp),
346   context_offset (Rsp),
347   context_offset (R8),
348   context_offset (R9),
349   context_offset (R10),
350   context_offset (R11),
351   context_offset (R12),
352   context_offset (R13),
353   context_offset (R14),
354   context_offset (R15),
355   context_offset (Rip),
356   context_offset (EFlags),
357   context_offset (SegCs),
358   context_offset (SegSs),
359   context_offset (SegDs),
360   context_offset (SegEs),
361   context_offset (SegFs),
362   context_offset (SegGs),
363   context_offset (FloatSave.FloatRegisters[0]),
364   context_offset (FloatSave.FloatRegisters[1]),
365   context_offset (FloatSave.FloatRegisters[2]),
366   context_offset (FloatSave.FloatRegisters[3]),
367   context_offset (FloatSave.FloatRegisters[4]),
368   context_offset (FloatSave.FloatRegisters[5]),
369   context_offset (FloatSave.FloatRegisters[6]),
370   context_offset (FloatSave.FloatRegisters[7]),
371   context_offset (FloatSave.ControlWord),
372   context_offset (FloatSave.StatusWord),
373   context_offset (FloatSave.TagWord),
374   context_offset (FloatSave.ErrorSelector),
375   context_offset (FloatSave.ErrorOffset),
376   context_offset (FloatSave.DataSelector),
377   context_offset (FloatSave.DataOffset),
378   context_offset (FloatSave.ErrorSelector)
379   /* XMM0-7 */ ,
380   context_offset (Xmm0),
381   context_offset (Xmm1),
382   context_offset (Xmm2),
383   context_offset (Xmm3),
384   context_offset (Xmm4),
385   context_offset (Xmm5),
386   context_offset (Xmm6),
387   context_offset (Xmm7),
388   context_offset (Xmm8),
389   context_offset (Xmm9),
390   context_offset (Xmm10),
391   context_offset (Xmm11),
392   context_offset (Xmm12),
393   context_offset (Xmm13),
394   context_offset (Xmm14),
395   context_offset (Xmm15),
396   /* MXCSR */
397   context_offset (FloatSave.MxCsr)
398 };
399 #undef context_offset
400
401 #endif /* __x86_64__ */
402
403 /* Fetch register from gdbserver regcache data.  */
404 static void
405 i386_fetch_inferior_register (struct regcache *regcache,
406                               win32_thread_info *th, int r)
407 {
408   char *context_offset = (char *) &th->context + mappings[r];
409
410   long l;
411   if (r == FCS_REGNUM)
412     {
413       l = *((long *) context_offset) & 0xffff;
414       supply_register (regcache, r, (char *) &l);
415     }
416   else if (r == FOP_REGNUM)
417     {
418       l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
419       supply_register (regcache, r, (char *) &l);
420     }
421   else
422     supply_register (regcache, r, context_offset);
423 }
424
425 /* Store a new register value into the thread context of TH.  */
426 static void
427 i386_store_inferior_register (struct regcache *regcache,
428                               win32_thread_info *th, int r)
429 {
430   char *context_offset = (char *) &th->context + mappings[r];
431   collect_register (regcache, r, context_offset);
432 }
433
434 static const unsigned char i386_win32_breakpoint = 0xcc;
435 #define i386_win32_breakpoint_len 1
436
437 static void
438 i386_arch_setup (void)
439 {
440 #ifdef __x86_64__
441   init_registers_amd64 ();
442   win32_tdesc = tdesc_amd64;
443 #else
444   init_registers_i386 ();
445   win32_tdesc = tdesc_i386;
446 #endif
447 }
448
449 struct win32_target_ops the_low_target = {
450   i386_arch_setup,
451   sizeof (mappings) / sizeof (mappings[0]),
452   i386_initial_stuff,
453   i386_get_thread_context,
454   i386_set_thread_context,
455   i386_thread_added,
456   i386_fetch_inferior_register,
457   i386_store_inferior_register,
458   i386_single_step,
459   &i386_win32_breakpoint,
460   i386_win32_breakpoint_len,
461   i386_supports_z_point_type,
462   i386_insert_point,
463   i386_remove_point,
464   i386_stopped_by_watchpoint,
465   i386_stopped_data_address
466 };