1/* Copyright (C) 2007 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
21#define FCS_REGNUM 27
22#define FOP_REGNUM 31
23
24#define FLAG_TRACE_BIT 0x100
25
26static unsigned dr[8];
27
28static int debug_registers_changed = 0;
29static int debug_registers_used = 0;
30
31static void
32i386_initial_stuff (void)
33{
34  memset (&dr, 0, sizeof (dr));
35  debug_registers_changed = 0;
36  debug_registers_used = 0;
37}
38
39static void
40i386_get_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
41{
42  th->context.ContextFlags = \
43    CONTEXT_FULL | \
44    CONTEXT_FLOATING_POINT | \
45    CONTEXT_EXTENDED_REGISTERS | \
46    CONTEXT_DEBUG_REGISTERS;
47
48  GetThreadContext (th->h, &th->context);
49
50  debug_registers_changed = 0;
51
52  if (th->tid == current_event->dwThreadId)
53    {
54      /* Copy dr values from the current thread.  */
55      dr[0] = th->context.Dr0;
56      dr[1] = th->context.Dr1;
57      dr[2] = th->context.Dr2;
58      dr[3] = th->context.Dr3;
59      dr[6] = th->context.Dr6;
60      dr[7] = th->context.Dr7;
61    }
62}
63
64static void
65i386_set_thread_context (win32_thread_info *th, DEBUG_EVENT* current_event)
66{
67  if (debug_registers_changed)
68    {
69      th->context.Dr0 = dr[0];
70      th->context.Dr1 = dr[1];
71      th->context.Dr2 = dr[2];
72      th->context.Dr3 = dr[3];
73      /* th->context.Dr6 = dr[6];
74	 FIXME: should we set dr6 also ?? */
75      th->context.Dr7 = dr[7];
76    }
77
78  SetThreadContext (th->h, &th->context);
79}
80
81static void
82i386_thread_added (win32_thread_info *th)
83{
84  /* Set the debug registers for the new thread if they are used.  */
85  if (debug_registers_used)
86    {
87      th->context.ContextFlags = CONTEXT_DEBUG_REGISTERS;
88      GetThreadContext (th->h, &th->context);
89
90      th->context.Dr0 = dr[0];
91      th->context.Dr1 = dr[1];
92      th->context.Dr2 = dr[2];
93      th->context.Dr3 = dr[3];
94      /* th->context.Dr6 = dr[6];
95	 FIXME: should we set dr6 also ?? */
96      th->context.Dr7 = dr[7];
97
98      SetThreadContext (th->h, &th->context);
99      th->context.ContextFlags = 0;
100    }
101}
102
103static void
104i386_single_step (win32_thread_info *th)
105{
106  th->context.EFlags |= FLAG_TRACE_BIT;
107}
108
109/* An array of offset mappings into a Win32 Context structure.
110   This is a one-to-one mapping which is indexed by gdb's register
111   numbers.  It retrieves an offset into the context structure where
112   the 4 byte register is located.
113   An offset value of -1 indicates that Win32 does not provide this
114   register in it's CONTEXT structure.  In this case regptr will return
115   a pointer into a dummy register.  */
116#define context_offset(x) ((int)&(((CONTEXT *)NULL)->x))
117static const int mappings[] = {
118  context_offset (Eax),
119  context_offset (Ecx),
120  context_offset (Edx),
121  context_offset (Ebx),
122  context_offset (Esp),
123  context_offset (Ebp),
124  context_offset (Esi),
125  context_offset (Edi),
126  context_offset (Eip),
127  context_offset (EFlags),
128  context_offset (SegCs),
129  context_offset (SegSs),
130  context_offset (SegDs),
131  context_offset (SegEs),
132  context_offset (SegFs),
133  context_offset (SegGs),
134  context_offset (FloatSave.RegisterArea[0 * 10]),
135  context_offset (FloatSave.RegisterArea[1 * 10]),
136  context_offset (FloatSave.RegisterArea[2 * 10]),
137  context_offset (FloatSave.RegisterArea[3 * 10]),
138  context_offset (FloatSave.RegisterArea[4 * 10]),
139  context_offset (FloatSave.RegisterArea[5 * 10]),
140  context_offset (FloatSave.RegisterArea[6 * 10]),
141  context_offset (FloatSave.RegisterArea[7 * 10]),
142  context_offset (FloatSave.ControlWord),
143  context_offset (FloatSave.StatusWord),
144  context_offset (FloatSave.TagWord),
145  context_offset (FloatSave.ErrorSelector),
146  context_offset (FloatSave.ErrorOffset),
147  context_offset (FloatSave.DataSelector),
148  context_offset (FloatSave.DataOffset),
149  context_offset (FloatSave.ErrorSelector),
150  /* XMM0-7 */
151  context_offset (ExtendedRegisters[10 * 16]),
152  context_offset (ExtendedRegisters[11 * 16]),
153  context_offset (ExtendedRegisters[12 * 16]),
154  context_offset (ExtendedRegisters[13 * 16]),
155  context_offset (ExtendedRegisters[14 * 16]),
156  context_offset (ExtendedRegisters[15 * 16]),
157  context_offset (ExtendedRegisters[16 * 16]),
158  context_offset (ExtendedRegisters[17 * 16]),
159  /* MXCSR */
160  context_offset (ExtendedRegisters[24])
161};
162#undef context_offset
163
164/* Fetch register from gdbserver regcache data.  */
165static void
166i386_fetch_inferior_register (win32_thread_info *th, int r)
167{
168  char *context_offset = (char *) &th->context + mappings[r];
169
170  long l;
171  if (r == FCS_REGNUM)
172    {
173      l = *((long *) context_offset) & 0xffff;
174      supply_register (r, (char *) &l);
175    }
176  else if (r == FOP_REGNUM)
177    {
178      l = (*((long *) context_offset) >> 16) & ((1 << 11) - 1);
179      supply_register (r, (char *) &l);
180    }
181  else
182    supply_register (r, context_offset);
183}
184
185/* Store a new register value into the thread context of TH.  */
186static void
187i386_store_inferior_register (win32_thread_info *th, int r)
188{
189  char *context_offset = (char *) &th->context + mappings[r];
190  collect_register (r, context_offset);
191}
192
193struct win32_target_ops the_low_target = {
194  sizeof (mappings) / sizeof (mappings[0]),
195  i386_initial_stuff,
196  i386_get_thread_context,
197  i386_set_thread_context,
198  i386_thread_added,
199  i386_fetch_inferior_register,
200  i386_store_inferior_register,
201  i386_single_step,
202  NULL, /* breakpoint */
203  0, /* breakpoint_len */
204  "i386" /* arch_string */
205};
206